Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
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
Project: cocalc-sagemath-dev-slelievre
Views: 418346/****************************************************************************1**2*A extra_relations.c ANUPQ source Eamonn O'Brien3**4*Y Copyright 1995-2001, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany5*Y Copyright 1995-2001, School of Mathematical Sciences, ANU, Australia6**7*/89#include "pq_defs.h"10#include "pcp_vars.h"11#include "constants.h"12#include "pq_functions.h"13#include "exp_vars.h"1415#if defined(GROUP)1617/* this procedure collect extra relations which hold in the group;1819it may be used as an exponent check routine for certain20Burnside computations;2122if pcp->extra_relations = 0 there are no extra relations;2324if pcp->extra_relations > 0, the extra relations specify that25certain pcp words have exponent pcp->extra_relations -- those26normal pcp words with weights from pcp->start_wt to end_class;2728if pcp->end_wt > 0, end_class is set to the minimum of pcp->cc and29this value;3031if both pcp->end_wt and pcp->start_wt are 0, this ensures that the32group has exponent pcp->extra_relations;3334if ALL_WORDS is chosen, then the routine generates a complete35list of the normal words needed in exponent checking whose36weights lie within the chosen bounds;3738if REDUCED_LIST is chosen, it is assumed that all redundant39relations in the queue are later closed under supplied40automorphisms which must contain a generating set for the41appropriate general linear group;4243if INITIAL_SEGMENT is chosen, the routine will read in a word44and only generate all those words needed for exponent checking45which have this word as a proper initial segment;4647any redundancies obtained by echelonising the members of this48list are added to the supplied queue;4950there are a number of options in this code which are selected51according to the value of the following variables:5253if exp_flag->process is FALSE, generate the list of words but do54not process the elements; if diagnostic output, then print out55all words which will be collected;5657if exp_flag->complete is TRUE and diagnostic output is chosen,58then print out all of the words of the appropriate weight59generated and not just those which survive the conjugacy and60other tests;6162hence, if you want a listing of all of the words generated using the63back-track search, you should set both flags TRUE;6465if exp_flag->partitions is TRUE, print the weight partitions66of the generated words; */676869#define MCLASS 100007071int initial_length; /* length of initial segment */72int least_weight; /* lower bound on weight of remaining letters */73int max_weight; /* upper bound on weight of remaining letters */74int initial_weight; /* weight of initial segment */75int first_entry; /* lower bound on new letters in word */76int least_entry; /* lower bound on remaining new letters in word */77int max_entry; /* upper bound on new letters in word */7879/* read in the initial segment to be used in generating the words */8081static void82read_initial_segment(int *initial, int *initial_coeff, struct pcp_vars *pcp)83{84register int *y = y_address;8586register int i;87int lower_bound; /* lower bound on next letter in word */88int lower_bound_weight; /* lower bound on weight of next letter */8990#include "access.h"9192/* read in details of the initial segment of the words to be processed */93read_value(94TRUE, "Input length of initial segment of words: ", &initial_length, 0);9596lower_bound = 0;97if (initial_length != 0) {98printf("Input initial segment of words as a generator exponent list: ");99for (i = 1; i < initial_length; ++i) {100read_value(FALSE, "", &initial[i], lower_bound + 1);101read_value(FALSE, "", &initial_coeff[i], 1);102lower_bound = initial[i];103}104read_value(FALSE, "", &initial[i], lower_bound + 1);105read_value(TRUE, "", &initial_coeff[i], 1);106lower_bound = initial[i];107}108109/* find initial weight */110initial_weight = 0;111for (i = 1; i <= initial_length; ++i)112initial_weight += initial_coeff[i] * WT(y[pcp->structure + initial[i]]);113114/* all other entries in this word must have weight as least115as great as the last letter of the initial segment */116if (lower_bound == 0)117lower_bound_weight = 1;118else119lower_bound_weight = MAX(1, WT(y[pcp->structure + lower_bound]));120121read_value(TRUE,122"Input lower bound for weight of remaining letters: ",123&least_weight,124lower_bound_weight);125126/* first entry in the remainder of word */127first_entry = y[pcp->clend + MIN(least_weight - 1, pcp->cc)];128129/* the first new letter must be larger than the last letter130of the initial segment */131first_entry = MAX(lower_bound, first_entry);132133/* if using automorphisms and initial segment has length 0,134we skip all but first of those pcp generators of weight 1 */135least_entry =136(pcp->m != 0 && initial_length == 0) ? y[pcp->clend + 1] : first_entry;137138read_value(TRUE,139"Input upper bound for weight of remaining letters: ",140&max_weight,141least_weight);142143max_entry = pcp->ccbeg;144if (max_weight < pcp->cc)145max_entry = y[pcp->clend + max_weight] + 1;146}147148void extra_relations(struct exp_vars *exp_flag, struct pcp_vars *pcp)149{150register int *y = y_address;151152register int nmr_words; /* number of normal words powered in class */153register int length; /* number of generators in normal word */154register int exp_length; /* sum of exponents in normal word */155register int nextg; /* next generator added to normal word */156register int w; /* weight of generator in normal word */157register int weight; /* weight of normal word */158register int wt_gen1; /* weight of first generator in normal word */159register int gen_i; /* ith generator in normal word */160register Logical exit; /* exit from loop? */161162int gen[MCLASS + 1]; /* generators of normal word */163int coeff[MCLASS + 1]; /* exponents of these generators */164int initial[MCLASS + 1]; /* generators of initial normal word */165int initial_coeff[MCLASS + 1]; /* exponents of these generators */166167register int extra_relations = pcp->extra_relations;168register int structure = pcp->structure;169register int lastg = pcp->lastg;170register int prime = pcp->p;171register int pm1 = pcp->pm1;172173register int end_class; /* end class for check */174register int class;175register int entry;176register int i, j;177int *queue;178char *s;179180FILE *RelationList;181182#include "access.h"183184if (extra_relations == 0)185return;186187/* relation file */188if (exp_flag->word_list)189RelationList = OpenFile("Relation_list", "w");190191/* determine whether the supplied exponent is192valid and what classes must be checked */193i = 0;194j = extra_relations;195while (j > 1) {196if (MOD(j, prime) != 0) {197text(14, extra_relations, 0, 0, 0);198pcp->valid = FALSE;199return;200}201++i;202j /= prime;203}204205if (pcp->cc <= i)206return;207end_class = pcp->cc;208if (pcp->end_wt != 0)209end_class = MIN(end_class, pcp->end_wt);210211if (exp_flag->list == ALL_WORDS || exp_flag->list == REDUCED_LIST) {212initial_length = 0;213initial_weight = 0;214first_entry = 0;215least_entry = (exp_flag->list == REDUCED_LIST) ? y[pcp->clend + 1] : 0;216max_entry = pcp->ccbeg;217} else {218read_initial_segment(initial, initial_coeff, pcp);219}220queue = exp_flag->queue;221222/* process each relevant class in turn --223using a backtrack process, build up normal words in the pcp224generators of the group which have weight equal to class;225each word has the general form226227gen[1]^coeff[1] * gen[2]^coeff[2] * ... * gen[length]^coeff[length]228229where gen[1], ..., gen[length] are pcp generators with230gen[1] < gen[2] < ... < gen[length], coeff[1] = 1,231and 0 < coeff[i] < prime for i = 2,...,length;232233we generate only all words with weight equal to class and234coeff[1] = 1; normal words with coeff[1] > 1 are powers235of normal words with coeff[1] = 1, and so they have the236same orders as those with coeff[1] = 1;237238if REDUCED_LIST is chosen, we enforce the additional239requirement that gen[i] has weight at least 2 for240all i >= 2, and gen[1] = 1 or gen[1] has weight at least 2;241242if INITIAL_SEGMENT is chosen, we enforce the additional243requirement that each word has the supplied proper244initial segment;245246we apply some commutator calculus to eliminate some of247the words; those not eliminated are raised to the power248extra_relations and then the result is echelonised */249250for (class = MAX(1, pcp->start_wt); class <= end_class; ++class) {251252nmr_words = 0;253length = initial_length;254weight = initial_weight;255256/* set up the initial-segment of the word */257for (i = 1; i <= initial_length; ++i) {258gen[i] = initial[i];259coeff[i] = initial_coeff[i];260}261262nextg = first_entry + 1;263w = WT(y[structure + nextg]);264265do {266/* backtrack process -- start to construct the next normal word */267exit = FALSE;268while (weight + w > class || nextg >= max_entry) {269270/* if length = 0, we have finished this class */271exit = (length == initial_length);272if (exit)273break;274275/* strip off last generator from the normal word and276decrease the weight of the word accordingly */277nextg = gen[length];278if (--coeff[length] == 0)279--length;280weight -= WT(y[structure + nextg]);281282if (nextg >= 1 && nextg < least_entry)283/* nextg should now start with first generator of next weight */284nextg = least_entry + 1;285else286++nextg;287288w = WT(y[structure + nextg]);289}290if (exit)291break;292293/* add in nextg as last pcp generator with exponent294one of normal word; increase weight accordingly */295coeff[++length] = 1;296if (nextg > 1 && nextg <= least_entry) {297/* nextg should now start with first generator of weight 2 */298nextg = least_entry + 1;299w = WT(y[structure + nextg]);300}301gen[length] = nextg;302weight += w;303304/* keep extending normal word as long as its weight is < class */305while (weight < class) {306if (coeff[length] == pm1 || length == 1) {307/* add in a new pcp generator with exponent 1 */308coeff[++length] = 1;309++nextg;310if (nextg > 1 && nextg <= least_entry)311/* nextg now starts with first generator of next weight */312nextg = least_entry + 1;313gen[length] = nextg;314w = WT(y[structure + nextg]);315} else316/* add in another copy of nextg */317++coeff[length];318319/* update weight for new word */320weight += w;321}322323/* if weight > class, we have extended the normal324word too far, and we need to backtrack */325if (weight > class)326continue;327328/* if appropriate, print out weight partitions */329330if (exp_flag->partitions) {331printf("seq (");332for (i = 1; i < length; ++i)333for (j = 1; j <= coeff[i]; ++j)334printf("%d, ", WT(y[structure + gen[i]]));335336for (j = 1; j < coeff[length]; ++j)337printf("%d, ", WT(y[structure + gen[length]]));338printf("%d),\n", WT(y[structure + gen[length]]));339}340341if (exp_flag->complete) {342printf("Seek to collect power %d of the following word: ",343extra_relations);344for (i = 1; i <= length; ++i)345printf("%d^%d ", gen[i], coeff[i]);346printf("\n");347}348349/* we now have a normal word of weight class; run a number of350checks to establish if it is necessary to exponentiate it;351first, use commutator identities to possibly eliminate it;352353if the conditions in the if clause below are satisfied,354then the normal closure of nextg has prime exponent;355356if this is the case, we can express the normal word in357the form u * nextg, where u is a normal word of lower weight;358we assume by induction that u^extra_relations = 1,359and this, together with the fact that the normal360closure of nextg has exponent prime, implies that361(u * nextg)^extra_relations is a product of commutators362which have length at least extra_relations and which have363entries gen[1],..., gen[length]; we may also assume that364gen[i] occurs at least coeff[i] times for i = 1, ..., length365in each of these commutators;366367let exp_length = sum of coeff[i] for i = 1, ..., length;368if extra_relations > exp_length then these commutators369have extra entries of weight at least wt_gen1; check whether370the extra entries make the total weight of the commutators371exceed the current class; if so, the power of this word372is trivial */373374wt_gen1 = WT(y[structure + gen[1]]);375376if (prime * w >= pcp->cc && y[pcp->ppower + nextg] == 0) {377/* find the sum of the coefficients */378for (i = 1, exp_length = 0; i <= length; ++i)379exp_length += coeff[i];380if (weight + (extra_relations - exp_length) * wt_gen1 > pcp->cc) {381if (exp_flag->filter) {382printf("Filtered from list using normal closure\n");383}384continue;385}386}387388/* seek to eliminate conjugates and powers of words389which are tested at other times;390391the Felsch-Neubueser conjugacy class algorithm provides392a list of class representatives for a group described393by a pcp; these representatives have the property that394if a word occurs in the list, then any of its subwords395also occurs as a representative; the calculations listed396below allow us to recognise that certain words would397not occur in the list; if we can deduce that our398normal word, w, would not occur, we do not power w;399400in the iteration listed below, if gen_i = PART2(entry) or401PART3(entry) then gen[j] is a commutator or power of gen_i;402this means that our normal word, w, is a conjugate or a power403of another normal word which starts off with the same first404i generator-exponent pairs as w, but which does not have405gen[j] anywhere in it;406407note that this reduction is critically sensitive to408the way in which generators are numbered, and to the409way eliminations are carried out in this program;410411Michael Vaughan-Lee provided this refinement */412413/* first, find last generator in normal word with weight = wt_gen1 */414for (i = length; WT(y[structure + gen[i]]) > wt_gen1; --i)415;416417if (i != length) {418exit = FALSE;419gen_i = gen[i];420for (j = i + 1; j <= length && !exit; ++j) {421entry = y[structure + gen[j]];422exit = (gen_i == PART2(entry) || gen_i == PART3(entry));423}424if (exit) {425if (exp_flag->filter == TRUE)426printf("Filtered from list using conjugacy checks\n");427continue;428}429}430431/* we have a word to exponentiate */432++nmr_words;433434/* we may want to save all test words generated to435a relation file for later processing */436if (exp_flag->word_list) {437fprintf(RelationList, "%d ", extra_relations);438for (i = 1; i <= length; ++i)439for (j = 1; j <= coeff[i]; ++j)440fprintf(RelationList, "%d ", gen[i]);441fprintf(RelationList, ";\n");442}443444/* space is required for three collected parts set up in power */445if (is_space_exhausted(6 * lastg + 6, pcp))446return;447448structure = pcp->structure;449450/* put one copy of word into collected part in exponent-vector form */451for (i = 1; i <= lastg; ++i)452y[pcp->lused + i] = 0;453454for (i = 1; i <= length; ++i) {455nextg = gen[i];456y[pcp->lused + nextg] = coeff[i];457}458459/* if process flag is true, and the number of the word is higher460than supplied value, power the word and echelonise the result */461462if (exp_flag->process && nmr_words >= exp_flag->start_process) {463464power(extra_relations, pcp->lused, pcp);465466/* is the result trivial? if not, group has larger exponent */467if (exp_flag->check_exponent == TRUE) {468i = 1;469while (i <= lastg && exp_flag->all_trivial) {470exp_flag->all_trivial = (y[pcp->lused + i] == 0);471++i;472}473if (exp_flag->all_trivial == FALSE)474return;475}476477/* set second collected part trivial for echelonisation */478for (i = 1; i <= lastg; ++i)479y[pcp->lused + lastg + i] = 0;480481echelon(pcp);482}483484/* if appropriate, print out the normal word */485if (((pcp->fullop && pcp->eliminate_flag) ||486(pcp->diagn && exp_flag->process) ||487(pcp->diagn && !exp_flag->process && !exp_flag->filter)) &&488nmr_words >= exp_flag->start_process) {489s = exp_flag->process ? "Collected" : "Will collect";490printf("%s power %d of the following word: ", s, extra_relations);491for (i = 1; i <= length; ++i)492printf("%d^%d ", gen[i], coeff[i]);493printf("\n");494}495496if (pcp->redgen != 0 && pcp->m != 0)497queue[++exp_flag->queue_length] = pcp->redgen;498499/* report intermediate statistics */500if (exp_flag->report_unit && nmr_words % exp_flag->report_unit == 0) {501s = nmr_words == 1 ? "" : "s";502printf(503"%d relation%s of class %d collected\n", nmr_words, s, class);504}505506if (pcp->overflow || pcp->complete != 0 || pcp->newgen == 0)507return;508509} while (length != 0);510511/* if appropriate, report the number of words raised to power */512if (!exp_flag->process || exp_flag->report_unit || pcp->fullop ||513pcp->diagn)514text(13, nmr_words, class, exp_flag->process, 0);515}516517if (exp_flag->word_list)518CloseFile(RelationList);519}520521#endif522523524