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/**************************************************************************23control.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 Level 1 of ACE; i.e., an `easy to use' wrapper round the core17enumerator. Note that we choose to always free & then reallocate space for18the data structures. This is simple, but may be inefficient on a long19series of runs. It would be more efficient to keep track of how much20memory is currently allocated (for each structure), and only free/malloc21if the new structure is *bigger*!2223**************************************************************************/2425#include "al1.h"2627/******************************************************************28This is all the stuff declared in al1.h29******************************************************************/3031int workspace, workmult, *costable, tabsiz;32int *currrep, repsiz, repsp;33Logic asis;34char *grpname;35Wlist *rellst;36int trellen, ndgen, *gencol, *colgen;37Logic *geninv, galpha;38char algen[28];39int genal[27];40char *subgrpname;41Wlist *genlst;42int tgenlen;4344/******************************************************************45These are the Level 0 parameters `aliased' in Level 1.46******************************************************************/4748int rfactor1, cfactor1;49int pdsiz1, dedsiz1;50int maxrow1, ffactor1, nrinsgp1;5152/******************************************************************53void al1_freered(Wlist *w)5455Freely reduce all the words in a word list. Can reduce words to56zero length; we leave these in, since they'll be removed (&57deallocated) by _remempt() later. We keep it simple, and make58multiple passes through the word until there are no changes.59******************************************************************/6061void al1_freered(Wlist *w)62{63Wlelt *p;64Logic done;65int i,j;6667if (w == NULL || w->len == 0)68{ return; }6970for (p = w->first; p != NULL; p = p->next)71{72do73{74done = TRUE;7576for (i = 1; i <= p->len-1; i++)77{78if (p->word[i] == -p->word[i+1])79{80for (j = i; j <= p->len-2; j++)81{ p->word[j] = p->word[j+2]; }82p->len -= 2;8384done = FALSE;85break;86}87}88}89while (!done);90}91}9293/******************************************************************94void al1_cycred(Wlist *w)9596Cyclically reduce all the words in a word list. Since this is run97*after* _freered(), it can't introduce any 0-length words (think98about it!).99******************************************************************/100101void al1_cycred(Wlist *w)102{103Wlelt *p;104Logic done;105int j;106107if (w == NULL || w->len == 0)108{ return; }109110for (p = w->first; p != NULL; p = p->next)111{112do113{114done = TRUE;115116if ((p->len >= 2) && (p->word[1] == -p->word[p->len]))117{118for (j = 1; j <= p->len-2; j++)119{ p->word[j] = p->word[j+1]; }120p->len -= 2;121122done = FALSE;123}124}125while (!done);126}127}128129/******************************************************************130void al1_remempt(Wlist *w)131132Removes & deallocates zero-length or null words from the list. We133KISS, and do a `copy', dropping any empty words.134135Note: we make no attempt to remove duplicate words!136******************************************************************/137138void al1_remempt(Wlist *w)139{140Wlelt *newf, *newl, *old, *tmp;141int length;142143if (w == NULL || w->len == 0)144{ return; }145146newf = newl = NULL;147length = 0;148149for (old = w->first; old != NULL; )150{151tmp = old;152old = old->next;153154if (tmp->word == NULL || tmp->len == 0) /* blow away */155{156if (tmp->word != NULL)157{ free(tmp->word); }158free(tmp);159}160else /* move to `new' list */161{162if (newf == NULL)163{164newf = newl = tmp;165tmp->next = NULL;166}167else168{169newl->next = tmp;170newl = tmp;171tmp->next = NULL;172}173174length++;175}176}177178w->first = newf;179w->last = newl;180w->len = length;181}182183/******************************************************************184void al1_sort(Wlist *w)185186Sort word list into nondecreasing length order, using a stable (as187regards words of the same length) insertion sort. Note that the188list may contain duplicates, but is guaranteed *not* to contain any189empty words. We trace through the original list, stripping190elements off the front & inserting them in the new list in their191correct place. Note the speculative check to see if we can tag the192next element on at the end of the new list, instead of having to193traverse the list looking for its proper place; this means that194already sorted (or partially sorted) lists process fast.195******************************************************************/196197void al1_sort(Wlist *w)198{199Wlelt *newf, *newl;200Wlelt *old, *tmp;201Wlelt *curr, *currp;202203if (w == NULL || w->len < 2)204{ return; }205206/* The list contains >1 word! We move the first word to the new list,207remove it from the old list & make the new list `correct'. */208209newf = newl = w->first;210old = w->first->next;211newl->next = NULL;212213while (old != NULL)214{215tmp = old;216old = old->next;217218if (tmp->len >= newl->len) /* tag onto the end */219{220newl->next = tmp;221tmp->next = NULL;222newl = tmp;223}224else if (tmp->len < newf->len) /* tag onto the front */225{226tmp->next = newf;227newf = tmp;228}229else230{231/* At this point we have to scan the new list looking for tmp's232position; this *cannot* be the first or last, because of the233preceding checks. Further the new list must have at least two234elements in it by now (think about it!). */235236currp = newf;237curr = newf->next;238239while (tmp->len >= curr->len)240{241currp = curr;242curr = curr->next;243}244245tmp->next = curr;246currp->next = tmp;247}248}249250w->first = newf;251w->last = newl;252}253254/******************************************************************255Logic al1_chkinvol(void)256257First stage of involution checking / column allocation. Builds up258the initial version of the geninv[] array, based on the relator259list and the asis flag. If asis is false, any xx/x^2 (or whatever)260sets x to an involution. If asis is true, only a relator flagged261as an invol does the trick.262******************************************************************/263264Logic al1_chkinvol(void)265{266int i;267Wlelt *p;268269if (geninv != NULL)270{ free(geninv); }271if ((geninv = (int *)malloc((ndgen+1)*sizeof(Logic))) == NULL)272{ return(FALSE); }273274geninv[0] = FALSE; /* P.P.P. */275for (i = 1; i <= ndgen; i++)276{ geninv[i] = FALSE; }277278if (rellst != NULL && rellst->len > 0)279{280for (p = rellst->first; p != NULL; p = p->next)281{282if (p->len == 2 && p->word[1] == p->word[2])283{284if (asis)285{286if (p->invol)287{ geninv[abs(p->word[1])] = TRUE; }288}289else290{ geninv[abs(p->word[1])] = TRUE; }291}292}293}294295return(TRUE);296}297298/******************************************************************299Logic al1_cols(void)300301At this stage, geninv contains a list of the generators we would302*like* to treat as involutions, based on the presentation & the303asis flag. We now allocate the generators to columns, honouring304geninv & the order of entry, as far as we can. We *must* ensure305that the first two columns are either a generator & its inverse,306or two involutions. Once all this has been done, geninv & the307columns are *fixed* for the entire run. The invcol & gencol/colgen308arrays are created here; note the offsetting of the data in gencol,309to cope with -ve generator nos (inverses)!310******************************************************************/311312Logic al1_cols(void)313{314int i,j;315316/* First, we dispose of the anomalous case of one generator */317318if (ndgen == 1)319{320geninv[1] = FALSE;321ncol = 2;322323if (invcol != NULL)324{ free(invcol); }325if (gencol != NULL)326{ free(gencol); }327if (colgen != NULL)328{ free(colgen); }329if ( (invcol = (int *)malloc(3*sizeof(int))) == NULL ||330(gencol = (int *)malloc(3*sizeof(int))) == NULL ||331(colgen = (int *)malloc(3*sizeof(int))) == NULL )332{ return(FALSE); }333334invcol[0] = 0; /* P.P.P. */335invcol[1] = 2; /* col 2 is inv of col 1 */336invcol[2] = 1; /* col 1 is inv of col 2 */337338gencol[0] = 2; /* -gen #1 is col #2 */339gencol[1] = 0; /* P.P.P. */340gencol[2] = 1; /* +gen #1 is col #1 */341342colgen[0] = 0; /* P.P.P. */343colgen[1] = +1; /* col 1 is + gen 1 */344colgen[2] = -1; /* col 2 is - gen 1 */345346return(TRUE);347}348349/* As ndgen > 1, we can honour geninv. Allocate the required space,350since we now know that ncol will be 2*ndgen - #involns. */351352ncol = 2*ndgen;353for (i = 1; i <= ndgen; i++)354{355if (geninv[i])356{ ncol--; }357}358359if (invcol != NULL)360{ free(invcol); }361if (gencol != NULL)362{ free(gencol); }363if (colgen != NULL)364{ free(colgen); }365if ( (invcol = (int *)malloc((ncol+1)*sizeof(int))) == NULL ||366(gencol = (int *)malloc((2*ndgen+1)*sizeof(int))) == NULL ||367(colgen = (int *)malloc((ncol+1)*sizeof(int))) == NULL )368{ return(FALSE); }369370invcol[0] = 0; /* P.P.P. ... */371gencol[ndgen] = 0;372colgen[0] = 0;373374/* We can honour the generator ordering if the first generator is not an375involution, or if both the first two are. */376377if (!geninv[1] || (geninv[1] && geninv[2]))378{379j = 0;380for (i = 1; i <= ndgen; i++)381{382if (geninv[i]) /* involution, 1 col */383{384j++;385invcol[j] = j;386gencol[ndgen+i] = j;387gencol[ndgen-i] = j;388colgen[j] = +i;389}390else /* noninvolution, 2 cols */391{392j++;393invcol[j] = j+1;394gencol[ndgen+i] = j;395colgen[j] = +i;396j++;397invcol[j] = j-1;398gencol[ndgen-i] = j;399colgen[j] = -i;400}401}402403return(TRUE);404}405406/* We have to shuffle the columns. At this point, generator #1 is an407involution & #2 is not (think about it); we'll swap gen'rs 1 & 2, and408then honour the order. */409410invcol[1] = 2;411invcol[2] = 1;412invcol[3] = 3;413414gencol[ndgen+1] = 3;415gencol[ndgen-1] = 3;416gencol[ndgen+2] = 1;417gencol[ndgen-2] = 2;418419colgen[1] = +2;420colgen[2] = -2;421colgen[3] = +1;422423j = 3;424for (i = 3; i <= ndgen; i++) /* any more gen'rs? */425{426if (geninv[i]) /* involution, 1 col */427{428j++;429invcol[j] = j;430gencol[ndgen+i] = j;431gencol[ndgen-i] = j;432colgen[j] = +i;433}434else /* noninvolution, 2 cols */435{436j++;437invcol[j] = j+1;438gencol[ndgen+i] = j;439colgen[j] = +i;440j++;441invcol[j] = j-1;442gencol[ndgen-i] = j;443colgen[j] = -i;444}445}446447return(TRUE);448}449450/******************************************************************451void al1_getlen(void)452453Compute the total length of the relators and the generators.454******************************************************************/455456void al1_getlen(void)457{458Wlelt *p;459460trellen = 0;461if (rellst != NULL && rellst->len > 0)462{463for (p = rellst->first; p != NULL; p = p->next)464{ trellen += p->len; }465}466467tgenlen = 0;468if (genlst != NULL && genlst->len > 0)469{470for (p = genlst->first; p != NULL; p = p->next)471{ tgenlen += p->len; }472}473}474475/******************************************************************476void al1_baseexp(Wlelt *e)477478Compute exponent of word *e. btry is current attempt at base479length. This counts up, so get exp correct (i.e., as large as480possible). Originally used internally to save storage space (but481not time); now used for edps & print-out. Note that geninv is now482frozen & any involutary X's changed to x's, so we do not need to483worry about these when trying to find the max possible exponent.484******************************************************************/485486void al1_baseexp(Wlelt *e)487{488int i, j, btry;489490for (btry = 1; btry <= e->len/2; btry++)491{492if (e->len % btry == 0)493{ /* possible base length */494e->exp = e->len / btry;495496for (i = 1; i <= btry; i++)497{ /* for each gen in possible base */498for (j = i + btry; j <= e->len; j += btry)499{ /* for each poss copy */500if (e->word[i] != e->word[j])501{ goto eLoop; } /* mismatch, this e->exp failed */502}503}504505return; /* this e->exp is the exponent */506}507508eLoop:509; /* try next potential exponent */510}511512e->exp = 1; /* nontrivial exponent not found */513}514515/******************************************************************516void al1_getexp(void)517518Compute exponents of all words in both lists.519******************************************************************/520521void al1_getexp(void)522{523Wlelt *p;524525if (rellst != NULL && rellst->len > 0)526{527for (p = rellst->first; p != NULL; p = p->next)528{ al1_baseexp(p); }529}530531if (genlst != NULL && genlst->len > 0)532{533for (p = genlst->first; p != NULL; p = p->next)534{ al1_baseexp(p); }535}536}537538/******************************************************************539void al1_xtox(void)540541Change any involutary X to x.542******************************************************************/543544void al1_xtox(void)545{546Wlelt *p;547int i;548549if (rellst != NULL && rellst->len > 0)550{551for (p = rellst->first; p != NULL; p = p->next)552{553if (p->word != NULL && p->len > 0)554{555for (i = 1; i <= p->len; i++)556{557if (p->word[i] < 0 && geninv[-p->word[i]])558{ p->word[i] = -p->word[i]; }559}560}561}562}563564if (genlst != NULL && genlst->len > 0)565{566for (p = genlst->first; p != NULL; p = p->next)567{568if (p->word != NULL && p->len > 0)569{570for (i = 1; i <= p->len; i++)571{572if (p->word[i] < 0 && geninv[-p->word[i]])573{ p->word[i] = -p->word[i]; }574}575}576}577}578}579580/******************************************************************581Logic al1_setrel(void)582583Setup the relators for the enumerator. Note how we double up the584relators, so we can do `cyclic' scans efficiently. If ndrel=0, we585could skip this & leave the last setup present, but we choose to586tidy up.587******************************************************************/588589Logic al1_setrel(void)590{591Wlelt *p;592int i, j, first, second;593594if (relind != NULL)595{ free(relind); }596if ((relind = (int *)malloc((ndrel+1)*sizeof(int))) == NULL)597{ return(FALSE); }598relind[0] = -1; /* P.P.P. */599600if (relexp != NULL)601{ free(relexp); }602if ((relexp = (int *)malloc((ndrel+1)*sizeof(int))) == NULL)603{ return(FALSE); }604relexp[0] = 0; /* P.P.P. */605606if (rellen != NULL)607{ free(rellen); }608if ((rellen = (int *)malloc((ndrel+1)*sizeof(int))) == NULL)609{ return(FALSE); }610rellen[0] = 0; /* P.P.P. */611612if (relators != NULL)613{ free(relators); }614if ((relators = (int *)malloc(2*trellen*sizeof(int))) == NULL)615{ return(FALSE); }616617if (rellst != NULL && rellst->len > 0)618{619second = 0;620i = 1;621622for (p = rellst->first; p != NULL; p = p->next)623{624rellen[i] = p->len;625relexp[i] = p->exp;626first = second;627second = first + p->len;628relind[i] = first;629for (j = 1; j <= p->len; j++)630{ relators[first++] = relators[second++] = p->word[j]; }631i++;632}633}634635return(TRUE);636}637638/******************************************************************639Logic al1_setgen(void)640641Build the generator array. Again, if nsgpg=0 we could skip this.642******************************************************************/643644Logic al1_setgen(void)645{646Wlelt *p;647int i, j, first;648649if (subgindex != NULL)650{ free(subgindex); }651if ((subgindex = (int *)malloc((nsgpg+1)*sizeof(int))) == NULL)652{ return(FALSE); }653subgindex[0] = -1; /* P.P.P. */654655if (subglength != NULL)656{ free(subglength); }657if ((subglength = (int *)malloc((nsgpg+1)*sizeof(int))) == NULL)658{ return(FALSE); }659subglength[0] = 0; /* P.P.P. */660661if (subggen != NULL)662{ free(subggen); }663if ((subggen = (int *)malloc(tgenlen*sizeof(int))) == NULL)664{ return(FALSE); }665666if (genlst != NULL && genlst->len > 0)667{668first = 0;669i = 1;670671for (p = genlst->first; p != NULL; p = p->next)672{673subglength[i] = p->len;674subgindex[i] = first;675for (j = 1; j <= p->len; j++)676{ subggen[first++] = p->word[j]; }677i++;678}679}680681return(TRUE);682}683684/******************************************************************685Logic al1_bldedp(void)686687Build the edp data structure by scanning through the appropriate688portion of relators[] array for each relator. Note that *if* x is689to be treated as an involution, then relators of the form xx are690*not* included, since they yield nothing. However, relators of the691form xx *must* be included if x/X has more than 1 column allocated692in the table (ie, it is *not* treated as an involution). At this693stage, relators[] is still in the form of +/- gen'r nos. Note that694generators with single cols are being treated as involutions, and695any X's have been changed to x's, so we do not need to worry about696picking up inverses of 1-column generators.697698Remark: if defn:1 is active there are no involns, so *all* the699relators will be included.700******************************************************************/701702Logic al1_bldedp(void)703{704int start, col, gen, rel;705int b,e,i;706707if (edpbeg != NULL)708{ free(edpbeg); }709if (edpend != NULL)710{ free(edpend); }711if (edp != NULL)712{ free(edp); }713714if ( (edpbeg = (int *)malloc((ncol + 1)*sizeof(int))) == NULL ||715(edpend = (int *)malloc((ncol + 1)*sizeof(int))) == NULL ||716(edp = (int *)malloc(2*trellen*sizeof(int))) == NULL )717{ return(FALSE); }718edpbeg[0] = edpend[0] = -1; /* P.P.P. */719720start = 0;721for (col = 1; col <= ncol; col++)722{723edpbeg[col] = start; /* index of first edp, this col */724gen = colgen[col];725726for (rel = 1; rel <= ndrel; rel++)727{728/* b points to the beginning & e to the end of the base of (the first729copy of) relator rel. */730731b = relind[rel];732e = b-1 + rellen[rel]/relexp[rel];733734for (i = b; i <= e; i++)735{736if (relators[i] == gen)737{738if (!(b == e && relexp[rel] == 2 && invcol[col] == col))739{740edp[start++] = i;741edp[start++] = rellen[rel];742}743}744}745}746747if (start == edpbeg[col]) /* none found! */748{ edpbeg[col] = edpend[col] = -1; }749else750{ edpend[col] = start - 2; } /* index of last edp, this col */751}752753return(TRUE);754}755756/******************************************************************757void al1_transl(void)758759Translate the relators & generators from arrays in terms of760generators & inverses to arrays in terms of their associated column761numbers in the coset table.762******************************************************************/763764void al1_transl(void)765{766int i;767768for (i = 0; i < 2*trellen; i++)769{ relators[i] = gencol[ndgen+relators[i]]; }770771for (i = 0; i < tgenlen; i++)772{ subggen[i] = gencol[ndgen+subggen[i]]; }773}774775/******************************************************************776int al1_start(int mode)777778This is a wrapper for the enumerator (ie, al0_enum()). The mode779parameter indicates what we want to do; for the moment it is the780same as al0_enum()'s mode parameter, and is used to determine how781much `set-up' we have to do. (The order in which this setting-up782is done is *important*, since there are dependencies between the783various components.) The style parameter for the call will be784built from the values of rfactor1/cfactor1. Several other of the785Level 0 parameters are `aliased', to enable us to set them786`conveniently'. The return value is either a Level 1 error (ie, <=787-8192), or is that returned by _enum() (ie, > -8192).788789-8192 disallowed mode790-8193 memory problem791-8194 table too small792793Note: this routine (& all of Level 1) is written to be as general-794purpose as possible. In particular, it is *not* assumed that it795will be driven by the Level 2 interactive interface. So some of796the code may seem unnecessary, or needlessly complicated.797798Warning: this wrapper routine prevents some of the more obvious799`errors' that may occur when continuing/redoing enumerations.800However, it cannot pick up all such errors; either be very careful,801or use the Level 2 interactive interface. It is the caller's802responsibility to ensure that call sequences are valid!803804Warning: this routine may invalidate the current table, without805explicitly noting this fact. You *must* check the return value,806and only `believe' the table if this is >= -259 (ie, if the807enumerator is called and if it does something ok)!808******************************************************************/809810int al1_start(int mode)811{812int i, style;813814if (mode < 0 || mode > 2)815{ return(-8192); }816817/* If the mode is start or redo, then we have a (possibly) new or818(possibly) expanded (ie, *additional* relators/generators) presentation;819we have to do all the setup associated with the relator and generator820lists. If the mode is continue, we simply fall through. */821822if (mode == 0 || mode == 2)823{824/* If asis if false, then we freely/cyclically reduce the relators and825freely reduce the generators. (This may introduce (additional) empty826and/or duplicate words.) We then remove any empty words, irrespective827of the value of asis; duplicates are not (currently) removed. If asis828is false, we sort both lists. We *always* (re)set ndrel & nsgpg, since829it is not incumbent on a caller of _start() to set (& reset) these830correctly, and the length of the lists may have changed anyway!831832Note: we do *not* do any Tietze transformations, thus we are not free833to do, for example, xx --> 1 if x is an involution. */834835if (!asis)836{837al1_freered(rellst);838al1_freered(genlst);839al1_cycred(rellst);840}841842al1_remempt(rellst);843al1_remempt(genlst);844845if (!asis)846{847al1_sort(rellst);848al1_sort(genlst);849}850851if (rellst == NULL)852{ ndrel = 0; }853else854{ ndrel = rellst->len; }855if (genlst == NULL)856{ nsgpg = 0; }857else858{ nsgpg = genlst->len; }859}860861/* If we're in start mode, we need to build a list of which generators862are to be *treated* as involutions & do a column allocation (possibly863changing this list). These are *fixed* over a run (incl any redos), even864if later relators / values of asis would have changed it! */865866if (mode == 0)867{868if (!al1_chkinvol())869{ return(-8193); }870if (!al1_cols())871{ return(-8193); }872}873874/* If we're in start mode, then we have to build the empty table.875Although coset numbers are limited to 2G, the workspace can exceed the87632-bit limit; hence the messing around with floating-point to find the877max number of cosets given the number of columns. Note the extra878rounding down by 1 (for safety), and that coset #0 dne. Note the error879if there's not enough memory for at least 2 rows. */880881if (mode == 0)882{883tabsiz =884(int)(((double)workspace*(double)workmult)/(double)ncol) -1 -1;885if (tabsiz < 2)886{ return(-8194); }887888if (colptr != NULL)889{ free(colptr); }890if ((colptr = (int **)malloc((ncol + 1)*sizeof(int *))) == NULL)891{892tabsiz = 0;893maxrow = 1;894return(-8193);895}896897/* We now chop up our block of memory into (tabsiz+1)-sized chunks, one898for each column of the table. Whether or not this is the best way to899do things in moot (cf, caching). Recall that coset #0 is unused, and900note the (IP27/R10000) 64-bit addressing kludge! */901902colptr[0] = NULL;903for (i = 1; i <= ncol; i++)904{ colptr[i] = costable + (long)(i-1)*(long)(tabsiz+1); }905col1ptr = colptr[1];906col2ptr = colptr[2];907}908909/* In start/redo mode, we now have to (re)build the data structures910associated with the relators & generators. */911912if (mode == 0 || mode == 2)913{914/* The values in geninv have now been decided, and will be frozen for915this run. We now go through the relators/generators and change X to x916if x is to be *treated* as an involution. */917918al1_xtox();919920/* Calculate the total length of the relators & generators, and their921correct exponents. */922923al1_getlen();924al1_getexp();925926/* Build the doubled-up list of relators. */927928if (!al1_setrel())929{ return(-8193); }930931/* Build the list of generators. */932933if (!al1_setgen())934{ return(-8193); }935936/* Build the edp's. */937938if (!al1_bldedp())939{ return(-8193); }940941/* Change relator/generator lists to column-based form. */942943al1_transl();944}945946/* Having now done all the mode-specific setup, we embark on setting-up947those Level 0 parameters which are aliased at Level 1 (ie, those which948are not set *directly* by the user). We *assume* that the caller hasn't949done anything stupid, and try to honour the parameters requested. This950may be automatic, involve changing the enumerator's state on the fly,951cause an error return, or be silently ignored ... */952953/* Pd's are not preserved between calls, but we may need to honour a new954value of pdsiz. Values <=0 translate to the default of 256 and >0 is955honoured. It is up to the caller to ensure that pdsiz1 is a power of 2 &956is >=2. We don't bother malloc'ing if we already have enough memory.957Note that pdsiz is initialised to 0, so we are guaranteed to allocate958list space the first time through. */959960toppd = botpd = 0;961962if (pdsiz1 <= 0)963{ pdsiz1 = 256; }964965if (pdsiz1 < pdsiz)966{ pdsiz = pdsiz1; }967else if (pdsiz1 == pdsiz)968{ ; }969else970{971if (pdqrow != NULL)972{ free(pdqrow); }973if (pdqcol != NULL)974{ free(pdqcol); }975if ( (pdqcol = (int *)malloc(pdsiz1*sizeof(int))) == NULL ||976(pdqrow = (int *)malloc(pdsiz1*sizeof(int))) == NULL )977{978pdsiz = 0;979return(-8193);980}981982pdsiz = pdsiz1;983}984985/* A fill factor request of <= 0 picks up the default, anything else986is honoured. Levels 1/2 use ffactor1, which is always integral, so we987need to convert to float; in general, we can convert (int)<->(float)988without any problems, since ffactor1 is a `small' integer. */989990if (ffactor1 <= 0)991{992ffactor1 = 0;993ffactor = (float)((int)((5*(ncol + 2))/4));994}995else996{ ffactor = (float)ffactor1; }997998/* Deductions *may* be preserved betweens calls; we need to be careful to999preserve them if we're in continue mode, but we are free to empty the1000stack in start/redo mode (if we choose). We honour size increases using1001realloc (which acts like malloc if the existing pointer is null); this1002preserves the stack, in the absence of allocation errors. We honour size1003reductions simply by changing dedsiz, but we take care to note if we have1004to discard any deductions. dedsiz <=0 means the `smallish' default of10051000, and >0 is honoured. Comments similar to those for pdsiz1 apply. */10061007if (dedsiz1 <= 0)1008{ dedsiz1 = 1000; }10091010if (dedsiz1 < dedsiz)1011{1012if (topded >= dedsiz1) /* We've lost some deductions */1013{1014topded = dedsiz1-1;1015disded = TRUE;1016}1017dedsiz = dedsiz1;1018}1019else if (dedsiz1 == dedsiz)1020{ ; }1021else1022{1023if ( (dedrow = (int *)realloc(dedrow, dedsiz1*sizeof(int))) == NULL ||1024(dedcol = (int *)realloc(dedcol, dedsiz1*sizeof(int))) == NULL )1025{1026if (topded >= 0)1027{ disded = TRUE; }1028topded = -1;1029dedsiz = 0;1030return(-8193);1031}10321033dedsiz = dedsiz1;1034}10351036/* If nrinsgp1 <0 or nrinsgp >ndrel, then the default is to use all the1037relators. Otherwise the request is honoured. */10381039if (nrinsgp1 < 0 || nrinsgp1 > ndrel)1040{1041nrinsgp1 = -1;1042nrinsgp = ndrel;1043}1044else1045{ nrinsgp = nrinsgp1; }10461047/* If maxrow1 <= 1, or >= the number of rows allowed by the allocated1048memory, then maxrow defaults to the allocated memory size; else if it's1049>= the current value of maxrow, then the request is honoured. Otherwise,1050the request is honoured in start mode, and is honoured in redo &1051continue modes *provided* that it is at least as large as nextdf; it not,1052it's (re)set to nextdf-1 (here, maxrow >= 2, so we're OK as regards1053always allowing at least 2 rows in the table). Note that maxrow1 is1054initialised to 0 & nextdf to 2, so we're ok the first time through. */10551056if (maxrow1 <= 1 || maxrow1 >= tabsiz)1057{1058maxrow1 = 0;1059maxrow = tabsiz;1060}1061else if (maxrow1 >= maxrow)1062{ maxrow = maxrow1; }1063else1064{1065/* Note: 1 < maxrow1 < tabsiz and maxrow1 < maxrow */1066if (mode == 0) /* start mode */1067{ maxrow = maxrow1; }1068else /* redo/continue modes */1069{1070if (maxrow1 >= nextdf)1071{ maxrow = maxrow1; }1072else1073/* Note: 2 <= maxrow1 < nextdf <= maxrow+1 <= tabsiz+1 */1074{ maxrow = nextdf-1; } /* (re)set to CT size */1075}1076}10771078/* Pick up the required style & set the blocking factors. */10791080if (rfactor1 < 0)1081{1082if (cfactor1 < 0) /* R/C-style */1083{1084rfactor = -rfactor1;1085cfactor = -cfactor1;1086style = 0;1087}1088else if (cfactor1 == 0) /* R*-style */1089{1090rfactor = -rfactor1;1091cfactor = 0;1092style = 1;1093}1094else /* Cr-style */1095{1096rfactor = -rfactor1;1097cfactor = cfactor1;1098style = 2;1099}1100}1101else if (rfactor1 == 0)1102{1103if (cfactor1 < 0) /* C*-style */1104{1105/* C* is not yet implemented. For the moment, just use C-style. */11061107rfactor = 0;1108cfactor = -cfactor1;1109style = 5; /* ! */1110}1111else if (cfactor1 == 0) /* R/C-style (defaulted) */1112{1113/* R/C-style with defaulted parameters, which try to `balance' the1114R- & C-style activity. We set C-style to 1000 definitions, and1115assume that 1 in 2 of the positions in a relator yield a definition,1116hence the 2000 (ie, 2x1000). Note the care to prevent rfactor=0, as1117we're doing integer divisions. If there are no relators, we'll1118simply fill the columns of each row, hence the 1000/ncol. */11191120if (ndrel == 0)1121{ rfactor = 1 + 1000/ncol; }1122else1123{ rfactor = 1 + 2000/(1 + trellen); }1124cfactor = 1000;1125style = 0; /* Nota bene! */1126}1127else /* C-style */1128{1129rfactor = 0;1130cfactor = cfactor1;1131style = 5;1132}1133}1134else1135{1136if (cfactor1 < 0) /* Rc-style */1137{1138rfactor = rfactor1;1139cfactor = -cfactor1;1140style = 6;1141}1142else if (cfactor1 == 0) /* R-style */1143{1144rfactor = rfactor1;1145cfactor = 0;1146style = 7;1147}1148else /* CR-style */1149{1150rfactor = rfactor1;1151cfactor = cfactor1;1152style = 8;1153}1154}11551156/* And away we go ... */11571158if (msgctrl) /* normal message control */1159{ al1_prtdetails(1); }11601161/* Warning: DTT code */1162/*1163fprintf(fop, "DTT: mode = %d & style = %d\n", mode, style);1164*/11651166i = al0_enum(mode,style);11671168return i;1169}1170117111721173