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: 4183461/**************************************************************************23postproc.c4Colin Ramsay ([email protected])52 Mar 0167ADVANCED COSET ENUMERATOR, Version 3.00189Copyright 200010Centre for Discrete Mathematics and Computing,11Department of Mathematics and12Department of Computer Science & Electrical Engineering,13The University of Queensland, QLD 4072.14(http://staff.itee.uq.edu.au/havas)1516This is the post (enumeration) processing stuff for stand-alone ACE. Note17that many of the routines here could be considered as Level 0 or Level 118functions, since they perform general-purpose table manipulations; however,19some of them use Level 2's error-handler, so they couldn't be moved as they20stand to a lower level. They have been written to be as versatile and as21`robust' as possible, although Level 2 may not take full advantage of this.2223**************************************************************************/2425#include "al2.h"2627#include <ctype.h>2829/******************************************************************30void al2_oo(int arg)3132Find cosets with order a multiple of |arg|, modulo the subgroup.33If arg=0, print all orders. Otherwise, print the first (arg>0) or34all (arg<0) coset numbers with order a multiple of |arg|, along35with their reps.36******************************************************************/3738void al2_oo(int arg)39{40int i,j,k, aarg, ord;41Logic found;4243if (arg < 0)44{ aarg = -arg; }45else46{ aarg = arg; }4748found = FALSE;49for (i = 2; i < nextdf; i++)50{51if (COL1(i) >= 0)52{53if (al1_bldrep(i))54{55if ((ord = al1_ordrep()) == 0)56{ continue; }57if ((arg == 0) || (ord%aarg == 0))58{59if (!found)60{61found = TRUE;62fprintf(fop, " coset | order rep\n");63fprintf(fop, "--------+------------\n");64}6566fprintf(fop, "%7d | %6d ", i, ord);67for (j = 0; j < repsiz; j++)68{69k = colgen[currrep[j]]; /* generator number */70if (!galpha)71{ fprintf(fop, "%d ", k); }72else73{ fprintf(fop, "%c",74(k > 0) ? algen[k] : toupper(algen[-k])); }75}76fprintf(fop, "\n");7778if ((arg > 0) && (ord%aarg == 0))79{ break; }80}81}82else83{ al2_continue("unable to build coset rep've"); }84}85}8687if (!found)88{ fprintf(fop, "* Nothing found\n"); }89}9091/******************************************************************92Logic al2_normal(int cos)9394Coset cos is normalising if for the subgroup H = <w_1,...,w_s>,95then cos*w_j = cos (for all j=1...s). Return T if this is the96case, else F (incl. out-of-range/redundant).9798Warning: this routine traces thro the subgrp gens, using the99enumerator's data structure. Thus, it can only be used if the100al1_start() routine has been called & nsgpg has *not* been altered.101Similar remarks apply to al2_normcl().102******************************************************************/103104Logic al2_normal(int cos)105{106int s, *beg, *end, *pi, next;107108if (cos < 1 || cos >= nextdf || COL1(cos) < 0)109{ return(FALSE); }110111for (s = 1; s <= nsgpg; s++)112{113beg = &(subggen[subgindex[s]]);114end = beg-1 + subglength[s];115116next = cos;117for (pi = beg; pi <= end; pi++)118{119if ((next = CT(next,*pi)) == 0 || COL1(next) < 0)120{ return(FALSE); }121}122if (next != cos)123{ return(FALSE); }124}125126return(TRUE);127}128129/******************************************************************130void al2_sc(int arg)131132Print the stabilising cosets of the subgrp. arg>0 prints the first133arg of them, arg<0 prints the first |arg| + reps, and arg=0 prints134all of them + reps.135******************************************************************/136137void al2_sc(int arg)138{139int i,j,k, aarg;140Logic found;141142if (arg < 0)143{ aarg = -arg; }144else145{ aarg = arg; }146147found = FALSE;148for (i = 2; i < nextdf; i++)149{150if (COL1(i) >= 0)151{152if (al2_normal(i))153{154if (!found)155{156found = TRUE;157if (arg <= 0)158{ fprintf(fop, "Stabilising cosets (+ reps):\n"); }159else160{ fprintf(fop, "Stabilising cosets:\n"); }161}162163fprintf(fop, "%7d", i);164if (arg <= 0)165{166if (!al1_bldrep(i))167{ al2_continue("unable to build coset rep've"); }168fprintf(fop, " ");169for (j = 0; j < repsiz; j++)170{171k = colgen[currrep[j]];172if (!galpha)173{ fprintf(fop, "%d ", k); }174else175{ fprintf(fop, "%c",176(k > 0) ? algen[k] : toupper(algen[-k])); }177}178}179fprintf(fop, "\n");180181if ((aarg != 0) && (--aarg == 0))182{ break; }183}184}185}186187if (!found)188{ fprintf(fop, "* Nothing found\n"); }189}190191/******************************************************************192void al2_cycles(void)193194Print out the coset table in cycles (permutation representation).195This *must* only be called when a completed *and* compacted coset196table is present; ie, when a finite index has been computed & a197(final) CO phase has been run. The dispatcher code in parser.c198enforces this. Note the use of the sign bit to track processed199cosets for each generator.200201ToDo: what about faithfulness?!202******************************************************************/203204void al2_cycles(void)205{206int i, j, k, kn, t, length;207Logic id;208209for (j = 1; j <= ndgen; j++)210{211k = gencol[ndgen+j]; /* find the column k for generator j */212id = TRUE; /* assume action is the identity */213214if (!galpha) /* print lhs & record its length */215{216fprintf(fop, "%d = ", j);217length = al2_outlen(j) + 3;218}219else220{221fprintf(fop, "%c = ", algen[j]);222length = 4;223}224225for (i = 1; i <= nalive; i++)226{227if (CT(i, k) == i) /* skip if i is a one-cycle */228{229CT(i, k) = -i;230continue;231}232233/* have we used coset i in previous cycle? */234235if (CT((kn = i), k) < 0)236{ continue; }237238id = FALSE; /* action of generator not identity */239240/* no, trace out this cycle */241242length += al2_outlen(kn) + 1;243if (length < LLL)244{ fprintf(fop, "(%d", kn); }245else246{247fprintf(fop, "\n (%d", kn);248length = al2_outlen(kn) + 3;249}250251t = CT(kn, k);252CT(kn, k) = -t; /* mark this coset as used */253kn = t;254255while (CT(kn,k) > 0)256{257length += al2_outlen(kn) + 1;258if (length < LLL)259{ fprintf(fop, ",%d", kn); }260else261{262fprintf(fop, ",\n %d", kn);263length = al2_outlen(kn) + 2;264}265266t = CT(kn, k);267CT(kn, k) = -t;268kn = t;269}270271/* we have reached the end of the cycle */272273fprintf(fop, ")");274length++;275}276277if (id)278{ fprintf(fop, "identity\n"); }279else280{ fprintf(fop, "\n"); }281282/* change all the (negative) values in this column back to positive */283284for (i = 1; i <= nalive; i++)285{ CT(i, k) = -CT(i, k); }286}287}288289/******************************************************************290void al2_normcl(Logic build)291292Check normal closure. Trace g^-1 * w * g and g * w * g^-1 for all293group generators g and all subgroup generator words w, noting294whether we get back to coset 1 or not. Note that 1.w^g = 1 iff2951.Gwg = 1 iff 1.Gw = 1.G (hence the apparent switch in the sense of296first when we set it). If build is T, then the conjugates of subgroup297generators by group generators that cannot be traced to the subgroup298are added to the list of subgroup generators; the *user* has to rerun299the enumeration. Note that coset #1 is never redundant; however,300others may be, and the table may be incomplete.301302Note: if g has a finite order, say n, then G=g^{n-1}. So either303both or neither of gwG and Gwg are in the subgroup (ie, we need304check only one). However, g may have infinite/unknown order so,305in general, we have to check both.306307Remark: we choose to ignore those g/w pairs where the trace does308not complete. It could be argued that we should include them in309the list of added conjugates (as ACE2 did). If we did, this would310require definitions to be made during the rerun of the SG phase.311By including only those pairs which do trace, but not to 1, we312effectively introduce coincidences.313******************************************************************/314315void al2_normcl(Logic build)316{317int col, first, next, s, *beg, *end, *pi, j,k,l;318Logic found;319Wlist *list;320Wlelt *lelt;321322found = FALSE;323list = NULL;324325for (col = 1; col <= ncol; col++) /* all `significant' gen'rs */326{327if ((first = CT(1,invcol[col])) == 0 || COL1(first) < 0)328{ continue; } /* trace incomplete, next col */329330for (s = 1; s <= nsgpg; s++) /* all (original) subgrp gens */331{332beg = &subggen[subgindex[s]];333end = beg-1 + subglength[s];334335next = first;336for (pi = beg; pi <= end; pi++)337{338if ((next = CT(next,*pi)) == 0 || COL1(next) < 0)339{ goto next_s; } /* trace incomplete, next gen */340}341if (next == first)342{ continue; } /* closes, next gen */343344/* At this point, we know that the trace of s^col completes but does345not get back to 1. So we have a conjugate that's not in the subgrp. */346347found = TRUE; /* at least 1 conjugate not in sgp */348349k = colgen[col]; /* (signed) generator number */350if (!galpha)351{352fprintf(fop, "Conjugate by grp gen'r \"%d\" of", k);353fprintf(fop, " subgrp gen'r \"");354for (pi = beg; pi <= end; pi++)355{ fprintf(fop, " %d", colgen[*pi]); }356}357else358{359fprintf(fop, "Conjugate by grp gen'r \"%c\" of",360(k > 0) ? algen[k] : toupper(algen[-k]));361fprintf(fop, " subgrp gen'r \"");362for (pi = beg; pi <= end; pi++)363{364if ((l = colgen[*pi]) > 0)365{ fprintf(fop, "%c", algen[l]); }366else367{ fprintf(fop, "%c", toupper(algen[-l])); }368}369}370fprintf(fop, "\" not in subgrp\n");371372if (build)373{374if (list == NULL)375{376if ((list = al1_newwl()) == NULL)377{ al2_continue("unable to create new subgrp gen'r list"); }378}379380if ((lelt = al1_newelt()) == NULL)381{382al1_emptywl(list);383free(list);384al2_continue("unable to create subgrp gen'r list elt");385}386387lelt->len = subglength[s] + 2; /* gen'r + col/col^-1 */388if ((lelt->word = (int*)malloc((lelt->len+1)*sizeof(int))) == NULL)389{390al1_emptywl(list);391free(list);392free(lelt);393al2_continue("unable to create subgrp gen'r list elt word");394}395lelt->exp = 1;396397lelt->word[1] = -k;398for (pi = beg, j = 2; pi <= end; pi++, j++)399{ lelt->word[j] = colgen[*pi]; }400lelt->word[lelt->len] = k;401402al1_addwl(list,lelt);403}404405next_s:406;407}408}409410if (!found)411{ fprintf(fop, "* All (traceable) conjugates in subgroup\n"); }412413/* If list != NULL then we must have created a list with at least one new414subgrp gen'r; so found is T & genlst is non-NULL/non-empty! Append the415list of new gen'rs & update the enumeration status. */416417if (list != NULL)418{419al1_concatwl(genlst,list);420421nsgpg = genlst->len;422423okcont = FALSE;424tabinfo = tabindex = FALSE;425426fprintf(fop, "* Subgroup generators have been augmented\n");427}428}429430/******************************************************************431void al2_cc(int cos)432433cos is guaranteed (by the caller) to be a non-redundant coset in434the range 2..nextdf-1. Get its rep & add it to the subgroup gens.435******************************************************************/436437void al2_cc(int cos)438{439int i,j;440Wlelt *lelt;441442/* Build & printout the representative */443444if (!al1_bldrep(cos))445{ al2_continue("unable to build rep've"); }446447fprintf(fop, "Coset #%d: ", cos);448for (i = 0; i < repsiz; i++)449{450j = colgen[currrep[i]];451if (!galpha)452{ fprintf(fop, "%d ", j); }453else454{ fprintf(fop, "%c", (j > 0) ? algen[j] : toupper(algen[-j])); }455}456fprintf(fop, "\n");457458/* Add the rep to the subgroup generators */459460if ((lelt = al1_newelt()) == NULL)461{ al2_continue("unable to create new subgrp gen'r"); }462463lelt->len = repsiz;464if ((lelt->word = (int*)malloc((lelt->len+1)*sizeof(int))) == NULL)465{466free(lelt);467al2_continue("unable to create subgrp gen'r word");468}469lelt->exp = 1;470471for (i = 0; i < repsiz; i++)472{ lelt->word[i+1] = colgen[currrep[i]]; }473474/* Add the new element to the (possibly non-existent) gen list */475476if (genlst == NULL)477{478if ((genlst = al1_newwl()) == NULL)479{480free(lelt->word);481free(lelt);482al2_continue("unable to create subgrp gen'r list");483}484}485al1_addwl(genlst,lelt);486nsgpg++;487488/* Reset enumeration status & `remind' the user */489490okcont = FALSE;491tabinfo = tabindex = FALSE;492493fprintf(fop, "* Subgroup generators have been augmented\n");494}495496/******************************************************************497void al2_rc(int desire, int count)498499Try to find a nontrival subgroup with index a multiple of a desired500index `desire' by repeatedly putting randomly chosen cosets501coincident with coset 1 and seeing what happens. The special value502desire=0 accepts *any* non-trivial finite index, while desire=1503accepts *any* finite index. We use the (not very good, but ok for504our purposes) random number generator rand(), which returns numbers505in the range 0..32767 (ie, lower 15 bits). We take care to ensure506that we generate a `valid' coset to set coincident with #1. If an507attempt fails, we restore the original subgrp gens, rerun the508original enumeration, and try again (making up to count attempts in509all). We use the asis flag to prevent subgroup generator510reordering, so that we can easily blow away the added generators.511512Notes:513(i) This routine presupposes that an enumeration has already been514performed (this may or may not have yielded a finite index). The515presentation and all the control parameters (apart from asis) are516frozen at their current values during this call; only the subgroup517generator list is altered. Any redo (or start) calls to the518enumerator use the current settings, including any messaging.519(ii) This routine can take a *long* time.520(iii) On success, the presentation/table reflects the discovered521subgroup. On failure, it reflects the original status.522(iv) We try hard to ensure that the system is always left in a523consistent state, and that all errors are picked up. However, it524is *strongly* recommended that a positive result is checked (by525doing a complete enumeration), and that nothing is assumed about526the presentation/table on a negative result or on an error (note527that the call to al2_cc() could cause an error return).528(v) Note that the value of cos, before it is reduced modulo nextdf,529is limited to 30 bits (ie, 0..1073741823).530******************************************************************/531532void al2_rc(int desire, int count)533{534int r1, r2, cos, old, i, cnt;535Logic tmp;536Wlelt *p, *q;537538/* Record current status; asis flag & subgrp gen list */539540tmp = asis;541asis = TRUE;542old = nsgpg;543544for (cnt = 1; cnt <= count; cnt++) /* Try up to count times */545{546fprintf(fop, "* Attempt %d ...\n", cnt);547548while (TRUE) /* Try until success / too small */549{550do551{552r1 = rand();553r2 = rand();554cos = ((r1 << 15) + r2)%nextdf;555}556while (cos < 2 || COL1(cos) < 0);557558al2_cc(cos);559560/* This chunk of code, for redo, is pinched from the parser */561562al1_rslt(lresult = al1_start(2));563564if (lresult > 0 && sgdone)565{566okcont = TRUE;567tabinfo = tabindex = TRUE;568}569else if (lresult >= -259 && sgdone)570{571okcont = TRUE;572tabinfo = TRUE;573tabindex = FALSE;574}575else576{577okcont = FALSE;578tabinfo = tabindex = FALSE;579}580if (lresult < -260)581{ okredo = FALSE; }582583/* Try and sort out what happened! */584585if (!(okcont && okredo && tabinfo))586{587asis = tmp;588al2_restart("* An unknown problem has occurred");589}590591if (desire == 0)592{593if (tabindex && lresult > 1)594{595fprintf(fop, "* An appropriate subgroup has been found\n");596asis = tmp;597return;598}599if (tabindex && lresult == 1)600{ goto restore; }601}602else603{604if (tabindex && lresult%desire == 0)605{606fprintf(fop, "* An appropriate subgroup has been found\n");607asis = tmp;608return;609}610if (tabindex && lresult < desire)611{ goto restore; }612}613};614615/* Setup for another attempt */616617restore:618619fprintf(fop, "* Recalculating original table\n");620621/* Remove added subgroup generators (of which there is at least 1) */622623if (old == 0)624{625al1_emptywl(genlst);626nsgpg = 0;627}628else629{630for (i = 1, p = genlst->first; i < old; i++, p = p->next)631{ ; }632633q = p->next; /* Points to first added generator */634635genlst->last = p;636genlst->last->next = NULL;637genlst->len = nsgpg = old;638639for (p = q; p != NULL; )640{641q = p->next;642643if (p->word != NULL)644{ free(p->word); }645free(p);646647p = q;648}649}650651/* Rerun the (original) enumeration (using code pinched from the652parser), and then try to sort out what happened. */653654al1_rslt(lresult = al1_start(0));655656if (lresult > 0 && sgdone)657{658okcont = okredo = TRUE;659tabinfo = tabindex = TRUE;660}661else if (lresult >= -259 && sgdone)662{663okcont = okredo = TRUE;664tabinfo = TRUE;665tabindex = FALSE;666}667else668{669okcont = okredo = FALSE;670tabinfo = tabindex = FALSE;671}672673if (!(okcont && okredo && tabinfo))674{675asis = tmp;676al2_restart("* An unknown problem has occurred");677}678679if (desire == 0)680{681if (tabindex && lresult > 1)682{683fprintf(fop, "* The original subgroup is appropriate!\n");684asis = tmp;685return;686}687}688else689{690if (tabindex && lresult%desire == 0)691{692fprintf(fop, "* The original subgroup is appropriate!\n");693asis = tmp;694return;695}696}697698if (tabindex && lresult == 1)699{700asis = tmp;701al2_restart("* Unable to restore original status");702}703if (desire >= nalive)704{705asis = tmp;706al2_restart("* Unable to restore original status");707}708};709710/* Our efforts failed. The last time through the outer loop restored the711original subgrp gens & table, so just restore asis & print a message. */712713fprintf(fop, "* No success; original status restored\n");714asis = tmp;715}716717/******************************************************************718void al2_dw(Wlist *p)719720Delete the list of words given by intarr[] from the word list p.721Both intarr[] & *p are guaranteed to be non-empty.722******************************************************************/723724void al2_dw(Wlist *p)725{726int i,j;727Wlelt *old, *tmp;728729/* Check the 1st value, and then ensure that (any) others are strictly730increasing and don't exceed the list length. */731732if (intarr[0] < 1 || intarr[0] > p->len)733{ al2_continue("first argument out of range"); }734for (i = 1; i < intcnt; i++)735{736if (intarr[i] <= intarr[i-1] || intarr[i] > p->len)737{ al2_continue("bad argument list"); }738}739740/* Trace through the list, `moving' the required words & dropping those741not required (freeing their space). */742743old = p->first; /* Start at front of old list ... */744i = 0;745746j = 0; /* First deletion is position intarr[0] */747748p->first = p->last = NULL; /* Clear `new' list ... */749p->len = 0;750751while (old != NULL)752{753tmp = old; /* `Chop' head of old list off */754old = old->next;755i++; /* Current position */756757if (i == intarr[j]) /* Delete this one */758{759if (tmp->word != NULL)760{ free(tmp->word); }761free(tmp);762763j++;764}765else /* Keep this one */766{767if (p->first == NULL)768{ p->first = tmp; }769else770{ p->last->next = tmp; }771tmp->next = NULL;772p->last = tmp;773p->len++;774}775}776}777778/**************************************************************************779The stuff under here is all concerned with testing various equivalent780presentations; either doing a random selection thereof, or all of them. It781is guaranteed that the (top-level) routines are only called if the relator782list is non-empty. The code here is all very naive, but there is little783point in trying to be clever/efficient. Note that, no matter how we784cycle/invert/permute the relators, the data attached to each word (ie, its785length & exponent, and how it was entered) remains valid.786**************************************************************************/787788/******************************************************************789void al2_inv_rel(Wlelt *p)790791Formally invert the word pointed to by p.792******************************************************************/793794void al2_inv_rel(Wlelt *p)795{796int j,k, len;797798len = p->len;799800for (j = 1; j <= len/2; j++)801{802k = p->word[j];803p->word[j] = -p->word[len+1-j];804p->word[len+1-j] = -k;805}806if (len%2 == 1)807{ p->word[1 + len/2] = -p->word[1 + len/2]; }808}809810/******************************************************************811void al2_cyc_rel(Wlelt *p)812813Cycle the word pointed to by p by 1 position.814******************************************************************/815816void al2_cyc_rel(Wlelt *p)817{818int j,k;819820k = p->word[1];821for (j = 1; j <= p->len-1; j++)822{ p->word[j] = p->word[j+1]; }823p->word[p->len] = k;824}825826/******************************************************************827void al2_per_rel(void)828829Randomly pick a position in the relator list, and move it to the830front of the list. The list is guaranteed to contain at least 2831elements.832******************************************************************/833834void al2_per_rel(void)835{836Wlelt *p, *pp;837int c,i;838839c = 1 + rand()%rellst->len; /* 1 <= c <= rellst->len */840if (c == 1)841{ return; } /* do nothing */842843pp = rellst->first;844p = pp->next;845i = 2;846for ( ; i < c; i++)847{ pp = p; p = p->next; }848849if (rellst->last == p)850{851pp->next = NULL;852rellst->last = pp;853}854else855{ pp->next = p->next; }856857p->next = rellst->first;858rellst->first = p;859}860861/******************************************************************862void al2_munge_cyc(void)863void al2_munge_inv(void)864void al2_munge_per(void)865866These 3 routines implement random cyclings, inversions &867permutations of the relators respectively. Note that we have to868take a `guess' as to how many relator list element moves are needed869to `randomly' reorder the relators. The permutation becomes870progressively `better' the more runs we do.871******************************************************************/872873void al2_munge_cyc(void)874{875Wlelt *p;876int c;877878for (p = rellst->first; p != NULL; p = p->next)879{880if ((c = rand()%p->len) > 0)881{882while (c-- > 0)883{ al2_cyc_rel(p); }884}885}886}887888void al2_munge_inv(void)889{890Wlelt *p;891892for (p = rellst->first; p != NULL; p = p->next)893{894if (rand()%2 == 1)895{ al2_inv_rel(p); }896}897}898899void al2_munge_per(void)900{901int len = rellst->len;902903while ((len /= 2) >= 1)904{ al2_per_rel(); }905}906907/******************************************************************908void al2_rep(int cntrl, int cnt)909910Do cnt enumerations using random equivalent presentations. The 3911lsbs of cntrl control cycling, inverting & permuting respectively.912We turn messaging off, dump the relators *after* each run (ie,913after al1_start() processes them, so that we see what they actually914were for the run), and use asis to prevent al1_start() from915messing up the relator ordering.916******************************************************************/917918void al2_rep(int cntrl, int cnt)919{920Logic tmpa, tmpm;921922tmpa = asis;923asis = TRUE;924tmpm = msgctrl;925msgctrl = FALSE;926927while (cnt-- > 0)928{929if ((cntrl & 0x1) != 0)930{ al2_munge_cyc(); }931if ((cntrl & 0x2) != 0)932{ al2_munge_inv(); }933if ((cntrl & 0x4) != 0)934{ al2_munge_per(); }935936/* (Re)run the enumeration, and then try to sort out what happened. */937938lresult = al1_start(0);939fprintf(fop, "Group Relators: ");940al1_prtwl(rellst, 16);941fprintf(fop, ";\n");942al1_rslt(lresult);943944if (lresult > 0 && sgdone)945{946okcont = okredo = TRUE;947tabinfo = tabindex = TRUE;948}949else if (lresult >= -259 && sgdone)950{951okcont = okredo = TRUE;952tabinfo = TRUE;953tabindex = FALSE;954}955else956{957okcont = okredo = FALSE;958tabinfo = tabindex = FALSE;959}960961if (!(okcont && okredo && tabinfo))962{963asis = tmpa;964msgctrl = tmpm;965al2_restart("* An unknown problem has occurred");966}967}968969asis = tmpa;970msgctrl = tmpm;971}972973/******************************************************************974void al2_aep2(Wlelt *p, int *d)975976For this permutation, recursively do all cycles/inversions.977******************************************************************/978979void al2_aep2(Wlelt *p, int *d)980{981Logic flg;982int i,blen;983984if (p == NULL) /* End of list, run enumerator */985{986/* Run the enumeration, and then try to sort out what happened. */987988d[2]++;989lresult = al1_start(0);990991if (lresult > 0 && sgdone)992{993okcont = okredo = TRUE;994tabinfo = tabindex = TRUE;995}996else if (lresult >= -259 && sgdone)997{998okcont = okredo = TRUE;999tabinfo = TRUE;1000tabindex = FALSE;1001}1002else1003{1004okcont = okredo = FALSE;1005tabinfo = tabindex = FALSE;1006}10071008if (!(okcont && okredo && tabinfo))1009{1010asis = (Logic)d[0];1011msgctrl = (Logic)d[1];1012al2_restart("* An unknown problem has occurred");1013}10141015/* Did we get an index? Any new best/worst values? */10161017if (tabindex)1018{1019d[8]++;10201021flg = FALSE;1022if (maxcos < d[3])1023{1024d[3] = maxcos;1025flg = TRUE;1026}1027if (maxcos > d[4])1028{1029d[4] = maxcos;1030flg = TRUE;1031}1032if (totcos < d[5])1033{1034d[5] = totcos;1035flg = TRUE;1036}1037if (totcos > d[6])1038{1039d[6] = totcos;1040flg = TRUE;1041}1042if (flg)1043{1044fprintf(fop, "Group Relators: ");1045al1_prtwl(rellst, 16);1046fprintf(fop, ";\n");1047al1_rslt(lresult);1048}10491050/* DTT code: dump *all* totcos values */1051/*1052fprintf(fop, "DTT: totcos=%d\n", totcos);1053*/1054}1055}10561057/* Cycle and/or invert this word, and then recurse. Note the care to1058ensure that we always do just what is required; in particular, we must1059ensure we restore a word to its original form. Note that we correctly1060cope with cycling in the presence of non-1 exponents. We *cannot*1061suppress inverting (x)^n, if x is an involution, since the geninv[]1062array is recalculated by al1_start() & may change since we're1063manipulating asis. To implement this, we'd need to duplicate the code in1064the al1_chkinvol() function. In fact, there's no end to this, since1065inverting (ab)^n, if a & b are involutions, is equivalent to cycling it,1066and doing *both* is wasteful! */10671068else1069{1070blen = p->len/p->exp; /* Baselength of word */10711072if ((d[7] & 0x3) == 0) /* Do nothing */1073{ al2_aep2(p->next, d); }1074else if ((d[7] & 0x3) == 1) /* Cycle only */1075{1076for (i = 0; i < blen; i++)1077{1078al2_cyc_rel(p);1079al2_aep2(p->next, d);1080}1081}1082else if ((d[7] & 0x3) == 2) /* Invert only */1083{1084al2_aep2(p->next, d);1085al2_inv_rel(p);1086al2_aep2(p->next, d);1087al2_inv_rel(p);1088}1089else /* Cycle & invert */1090{1091for (i = 0; i < blen; i++)1092{1093al2_cyc_rel(p);1094al2_aep2(p->next, d);1095}1096al2_inv_rel(p);1097for (i = 0; i < blen; i++)1098{1099al2_cyc_rel(p);1100al2_aep2(p->next, d);1101}1102al2_inv_rel(p);1103}1104}1105}11061107/******************************************************************1108void al2_aep1(int *d, Wlelt *p)11091110Recursively generate the permutations, calling al2_aep2() for each1111one. p is a pointer to parent node of the unprocessed `tail' of1112rellst. rellst contains >1 elts & p is (initially) the 1st elt.1113The node pointed to by the parent node is put in all positions, and1114then we recurse. So 123 yields 321, 231, 213, 312, 132, 123.1115******************************************************************/11161117void al2_aep1(int *d, Wlelt *p)1118{1119Wlelt *t0, *t1;11201121if (p->next == NULL)1122{ al2_aep2(rellst->first, d); }1123else1124{1125/* Move the head of the unprocessed tail to all possible positions. */11261127t0 = p->next; /* Node being moved */1128p->next = t0->next; /* Slice it out ... */1129if (rellst->last == t0)1130{ rellst->last = p; }11311132/* The head ... */11331134t0->next = rellst->first;1135rellst->first = t0;11361137al2_aep1(d, p);11381139rellst->first = t0->next;11401141/* The middle ... */11421143for (t1 = rellst->first; t1 != p; t1 = t1->next)1144{1145t0->next = t1->next;1146t1->next = t0;11471148al2_aep1(d, p);11491150t1->next = t0->next;1151}11521153/* The tail (where it started) ... */11541155t0->next = p->next;1156p->next = t0;1157if (rellst->last == p)1158{ rellst->last = t0; }11591160al2_aep1(d, p->next);1161}1162}11631164/******************************************************************1165void al2_aep(int cntrl)11661167Do all enumerations using equivalent presentations; see comments1168for al2_rep(). To prevent having lots of global data floating1169around, we pass a pointer to the datum array, which contains:1170[0] original asis1171[1] original msgctrl1172[2] number of runs1173[3] min maxcos1174[4] max maxcos1175[5] min totcos1176[6] max totcos1177[7] cntrl1178[8] number of successes1179******************************************************************/11801181void al2_aep(int cntrl)1182{1183int datum[9];11841185/* Temporary code, until we split al1_start() and do the presentation1186altering in the middle. We need to ensure that the current presentation1187has been processed so that the word exponents are correctly set. We do1188this run using whatever the current setup is, *before* we set asis &1189turn messaging off. After this run, the exponents will be fixed.1190However, setting asis may screw up involutions (ie, whether or not we'd1191need to invert some relators, if requested). Note that this also sets1192maxrow to a valid U.B. for maxcos/totcos. */11931194fprintf(fop, "* Priming run ...\n");1195al1_rslt(lresult = al1_start(0));11961197if (lresult > 0 && sgdone)1198{1199okcont = okredo = TRUE;1200tabinfo = tabindex = TRUE;1201}1202else if (lresult >= -259 && sgdone)1203{1204okcont = okredo = TRUE;1205tabinfo = TRUE;1206tabindex = FALSE;1207}1208else1209{1210okcont = okredo = FALSE;1211tabinfo = tabindex = FALSE;1212}12131214if (!(okcont && okredo && tabinfo))1215{ al2_restart("* An unknown problem has occurred"); }12161217/* Start of the `proper' code. */12181219datum[0] = (int)asis;1220asis = TRUE;1221datum[1] = (int)msgctrl;1222msgctrl = FALSE;1223datum[2] = 0;1224datum[3] = maxrow+1;1225datum[4] = 0;1226datum[5] = maxrow+1;1227datum[6] = 0;1228datum[7] = cntrl;1229datum[8] = 0;12301231fprintf(fop, "* Equivalent runs ...\n");1232if ((cntrl & 0x4) == 0 || rellst->len < 2) /* No permutations */1233{ al2_aep2(rellst->first, datum); }1234else1235{ al2_aep1(datum, rellst->first); }12361237if (datum[8] == 0)1238{ fprintf(fop, "* There were no successes in %d runs\n", datum[2]); }1239else1240{1241fprintf(fop, "* There were %d successes in %d runs:\n",1242datum[8], datum[2]);1243fprintf(fop, "* maxcos=%d..%d, totcos=%d..%d\n",1244datum[3], datum[4], datum[5], datum[6]);1245}12461247asis = (Logic)datum[0];1248msgctrl = (Logic)datum[1];1249}1250125112521253