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/**************************************************************************23enum.c4Colin Ramsay ([email protected])520 Dec 0067ADVANCED 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 main enumeration stuff for the core coset enumerator.1718Note: many of the functions `borrow' the scanning code (R-style or C-style)19& the deduction processing code from one another. We do this for speed20(wrapping things up in a function can carry a significant penalty, and21generality `costs') or because the code in not _exactly_ the same (be22warned!). I sometimes don't bother commenting such copies as fully as I23might; check all copies for the full details. (This is a form of24distributed documentation!)2526**************************************************************************/2728#include "al0.h"2930/******************************************************************31This macro readies a new coset for use, and gathers some32statistics.33******************************************************************/3435#define NEXTC(kk) \36kk = nextdf; \37for (col = 1; col <= ncol; col++) \38{ CT(kk, col) = 0; } \39nextdf++; \40totcos++; \41if (++nalive > maxcos) \42{ maxcos = nalive; } \4344/******************************************************************45This is all the stuff declared in al0.h46******************************************************************/4748FILE *fop, *fip;49double begintime, endtime, deltatime, totaltime;50Logic msgctrl, msghol;51int msgincr, msgnext;52Logic mendel, rfill, pcomp;53int maxrow, rfactor, cfactor, comppc, nrinsgp, lahead;54int tlimit, hlimit, llimit, lcount;55int nalive, maxcos, totcos;56int chead, ctail;57int pdefn;58float ffactor;59int pdsiz, *pdqcol, *pdqrow, toppd, botpd;60int dedsiz, *dedrow, *dedcol, topded, dedmode;61Logic disded;62int *edp, *edpbeg, *edpend;63int ncol, **colptr, *col1ptr, *col2ptr, *invcol;64int ndrel, *relind, *relexp, *rellen, *relators;65int nsgpg, *subggen, *subgindex, *subglength;66Logic sgdone;67int knr, knh, nextdf;6869#ifdef AL0_STAT70int cdcoinc; /* primary D-coincidences in _cdefn()/_rpefn() */71int rdcoinc; /* primary R-coincidences in _rdefn()/_rpefn() */72int apcoinc; /* primary coincidences in _apply() */73int rlcoinc; /* primary coincidences in _rl() */74int clcoinc; /* primary coincidences in _cl() */75int xcoinc; /* calls to _coinc() */76int xcols12; /* calls to _cols12() */77int qcoinc; /* number of actual coincs queued */7879int xsave12; /* calls to SAVE12() */80int s12dup; /* number of duplicates */81int s12new; /* number of new ones */8283/* The number of column 1 table accesses for CREP is xcrep+crepred+crepwrk.84For COMPRESS, the number is xcomp+2*compwrk. */8586int xcrep; /* calls to CREP() */87int crepred; /* number involving redundant cosets */88int crepwrk; /* number of `links' followed */89int xcomp; /* calls to COMPRESS() */90int compwrk; /* number of `links' altered */9192int xsaved; /* calls to SAVED() */93int sdmax; /* max (used) size of dedn stack */94int sdoflow; /* number of dedn stack overflows */9596int xapply; /* calls to _apply() */97int apdedn; /* number of dedn in _apply() */98int apdefn; /* number of defn in _apply() */99100int rldedn; /* number of dedn in _rl() */101int cldedn; /* number of dedn in _cl() */102103int xrdefn; /* calls to _rdefn()/_rpefn() */104int rddedn; /* number of R-dedn in _rdefn()/_rpefn() */105int rddefn; /* number of defn in _rdefn()/_rpefn() */106int rdfill; /* number of fill in _rdefn()/_rpefn() */107108int xcdefn; /* calls to _cdefn() */109int cddproc; /* number of dedn processed (ie, unstacked) */110int cdddedn; /* number of coinc dedn (ie, dead) */111int cddedn; /* number of dedn (in dedn processing) */112int cdgap; /* number of gap of len 1 */113int cdidefn; /* number of immediate defn */114int cdidedn; /* number of immediate dedn */115int cdpdl; /* number of pd listed */116int cdpof; /* number of pdl overflows */117int cdpdead; /* number of dead pd */118int cdpdefn; /* number of pref defn */119int cddefn; /* number of defn */120#endif121122/******************************************************************123int al0_apply(int cos, int *beg, int *end, Logic defn, Logic save)124125Apply coset cos to the word stored in beg...end. If defn is true126then definitions are made to complete the trace, and if save is127true any definitions are saved on the deduction stack. This128routine is intended for `general' use during R-style scans, so it129does _not_ worry about fill-factors or short gaps, nor is there any130limit on the number of definitions made. It's main use is in the131subgroup generator & relators as generators phases (when defn132will be true, and save may be true or false).133134If a finite `index' is obtained, this is the return value. If an135overflow occurs, 0 is returned. Otherwise -1 is returned.136137Warning: cos _must_ be a valid (1...nextdf-1) & non-coincident138coset. This routine must _never_ be called if the coincidence139queue is non-empty (i.e., all coincidences must have been fully140processed).141******************************************************************/142143int al0_apply(int cos, int *beg, int *end, Logic defn, Logic save)144{145int i,j,k;146int *fwd, *bwd;147int col, ifront, iback, ji;148149INCR(xapply);150ifront = iback = cos;151152/* Forward scan, leaving ifront set to coset at left of leftmost hole in153relator or to the last coset in the relator if no hole. */154155for (fwd = beg; fwd <= end; fwd++)156{157if ((i = CT(ifront, *fwd)) > 0)158{ ifront = i; }159else160{ break; }161}162163/* If the scan completed, then i = ifront & iback = cos, and we'll fall164right through and check for a coincidence (i.e., has ifront cycled back165to cos or not?). Else, there's a hole & a backward scan is required. */166167if (i == 0)168{169for (bwd = end; bwd >= fwd; bwd--)170{171j = *bwd;172ji = invcol[j];173174if ((i = CT(iback, ji)) > 0)175{ iback = i; }176else /* Scan stalled */177{178if (bwd == fwd)179{180/* The backward scan has only one gap, so note the deduction to181complete the cycle. */182183CT(iback, ji) = ifront;184if (save)185{ SAVED(iback, ji); }186187/* Since bwd == fwd and there was a hole, then either188CT(ifront,j) is still 0, or it has been set by a `backward'189definition (particularly if j's an involution). If it has been190set (on-the-fly, so to speak), we need to setup correctly for a191possible coincidence. */192193if (CT(ifront,j) > 0)194{ ifront = CT(ifront,j); } /* May be a coincidence here */195else196{197CT(ifront,j) = iback;198ifront = iback; /* Prevent false coincidence */199}200201INCR(apdedn);202}203else if (defn) /* Define a new coset */204{205/* Note that, if j is an involution, and occurs next to itself,206then after the first defn, the remainder of the string of j's207will close. Note that if j^2 = 1 & j is _not_ being treated as208an involution, then `removing' it is a Tietze transformation, not209a free reduction! */210211if (nextdf > maxrow) /* Overflow */212{ return(0); }213NEXTC(k);214CT(iback,ji) = k;215CT(k,j) = iback;216if (save)217{ SAVED(iback,ji); }218219iback = k;220INCR(apdefn);221222if (msgctrl && --msgnext == 0)223{224msgnext = msgincr;225ETINT;226fprintf(fop, "AD: a=%d r=%d h=%d n=%d;",227nalive, knr, knh, nextdf);228MSGMID;229fprintf(fop, " m=%d t=%d\n", maxcos, totcos);230BTINT;231}232}233else234{ return(-1); } /* New coset definition disabled */235}236}237}238239/* If we get here, the scan has been completed. Check to see if we've240found a pair of coincident cosets. */241242if (ifront != iback)243{244INCR(apcoinc);245if ((i = al0_coinc(ifront,iback,save)) > 0)246{ return(i); }247}248249return(-1);250}251252/******************************************************************253static int al0_rl(int first, int last, Logic saved)254255Do an R-style lookahead from coset #first up to #last. We return256-1 if nothing exciting happens and >=1 if we get a finite `index'257(ie, collapse to 1). `Approx.' complexity is rl or rl^2. Note258that this (incl. its call to _coinc) does _not_ alter knr/knh,259although in may `invalidate' them. Lookahead _never_ makes _new_260definitions (so, it never overflows), but it may stack deductions,261if requested.262******************************************************************/263264static int al0_rl(int first, int last, Logic saved)265{266int row,rel,i,ii,j,k,l;267int *pj, *pk, *fwd, *bwd;268int ifront, iback;269270for (row = first; row <= last; row++)271{272if (COL1(row) >= 0)273{274for (rel = 1; rel <= ndrel; rel++)275{276j = (mendel ? rellen[rel]/relexp[rel] : 1);277for (k = 0; k < j; k++)278{279pj = &(relators[relind[rel]+k]);280pk = pj + rellen[rel]-1;281282/* <-- cancel indent; the code here is essentially al0_apply(). */283284ifront = iback = row;285286for (fwd = pj; fwd <= pk; fwd++)287{288if ((l = CT(ifront, *fwd)) > 0)289{ ifront = l; }290else291{ break; }292}293294if (l == 0)295{296for (bwd = pk; bwd >= fwd; bwd--)297{298i = *bwd;299ii = invcol[i];300301if ((l = CT(iback, ii)) > 0)302{ iback = l; }303else if (bwd == fwd)304{305CT(iback, ii) = ifront;306if (saved)307{ SAVED(iback, ii); }308309/* Since we're _not_ making definitions, there is no need to check310if CT(ifront,i) is still undefined. The _only_ case where it's311not is if ifront=iback & i=ii; ie, i's an involution & we've just312deduced that ifront.i=ifront. So, we may set CT(ifront,i) twice,313but that's rare & does no damage, and is cheaper than checking. */314315CT(ifront, i) = iback;316317INCR(rldedn);318goto next_k;319}320else321{ goto next_k; }322}323}324325if (ifront != iback)326{327INCR(rlcoinc);328if ((l = al0_coinc(ifront,iback,saved)) > 0)329{ return(l); }330}331332/* --> restore indent */333334if (COL1(row) < 0) /* We've become redundant */335{ goto next_row; }336337next_k:338;339}340}341}342next_row:343; /* Prevent non-ANSI warning */344}345346return(-1);347}348349/******************************************************************350static int al0_cl(int first, int last, Logic saved)351352Do a C-style `lookahead' over all the entries in the table from353row #first to row #last inclusive; ie, treat it as a deduction354stack. We may, or may not, save deductions, depending as we're in355R-style or C-style. Returned value & comments as for al0_rl().356`Approx.' complexity is rcl.357******************************************************************/358359static int al0_cl(int first, int last, Logic saved)360{361int row,col,beg,end,i,j,ji,k;362int *pj, *pk, *fwd, *bwd;363int ifront, iback;364365for (row = first; row <= last; row++)366{367if (COL1(row) >= 0)368{369for (col = 1; col <= ncol; col++)370{371if (CT(row,col) > 0)372{373if ((beg = edpbeg[col]) >= 0)374{375end = edpend[col];376for (i = beg; i <= end; i += 2)377{378pj = &(relators[edp[i]]);379pk = pj + edp[i+1]-1;380381/* <-- cancel indent; the code here is essentially al0_apply(). */382383ifront = iback = row;384385for (fwd = pj; fwd <= pk; fwd++)386{387if ((k = CT(ifront, *fwd)) > 0)388{ ifront = k; }389else390{ break; }391}392393if (k == 0)394{395for (bwd = pk; bwd >= fwd; bwd--)396{397j = *bwd;398ji = invcol[j];399400if ((k = CT(iback, ji)) > 0)401{ iback = k; }402else if (bwd == fwd)403{404CT(iback, ji) = ifront;405if (saved)406{ SAVED(iback, ji); }407408CT(ifront, j) = iback;409410INCR(cldedn);411goto next_i;412}413else414{ goto next_i; }415}416}417418if (ifront != iback)419{420INCR(clcoinc);421if ((k = al0_coinc(ifront,iback,saved)) > 0)422{ return(k); }423}424425/* --> restore indent */426427if (COL1(row) < 0) /* We've become redundant */428{ goto next_row; }429430next_i:431;432}433}434}435}436}437next_row:438; /* Prevent non-ANSI warning */439}440441return(-1);442}443444/******************************************************************445static int al0_rdefn(int cnt, Logic fillr, Logic saved)446447Start scanning through the relators at coset knr, making448definitions as necessary to close the scans. If coset knr closes449against all relators, we fill any empty slots in its row (if fillr450is set), bump knr up, and loop round to process the next row. On451overflow we return 0 (leaving knr unchanged & the row only452partially scanned) and on a finite index we return nalive. Up to453cnt rows will be scanned (either completely or partially). If454nothing `exciting' happens, we return -1. Deductions are stacked455if saved is true. If cnt <0 then an infinite number of rows will456be scanned (so we'll get an index or overflow). We try as far as457possible to exit with complete rows scanned, so we do not continue458scanning after we've processed cnt rows (although the next active459row could close without any definitions required, or, in fact, we460could have finished without knowing it).461462Note that a finite index is only correct if the table has no holes.463If we get knr = nextdf & there are holes, then one option open to464the control logic is to set knr to 1, and then rerun _rdefn() with465fillr set to fill the holes. (Of course, this _isn't_ what we466actually do in this situation, since a holy-table is precisely467what we'd expect if some of the generators don't appear in any of468the relators!)469******************************************************************/470471static int al0_rdefn(int cnt, Logic fillr, Logic saved)472{473int i, j, k, l, m, mi, n;474int *beg, *end, *fwd, *bwd;475int col, ifront, iback;476477INCR(xrdefn);478479/* Count current knr up if it's redundant and/or get an index. Note, we480check nextdf _first_ so that COL1(knr) (ie, CT(knr,1)) is defined. */481482while (knr < nextdf && COL1(knr) < 0)483{ knr++; }484if (knr == nextdf)485{ return(nalive); }486487while (cnt != 0)488{489/* Scan through all relators for this coset. The code here is490essentially the same as that in al0_apply. We inline for speed (and491flexibility; the code's not _exactly_ the same). */492493for (i = 1; i <= ndrel; i++)494{495j = (mendel ? rellen[i]/relexp[i] : 1);496for (k = 0; k < j; k++)497{498499/* <-- cancel indent */500501/* Setup start & stop positions for scan, and the coset at the current502scan positions. */503504beg = &(relators[relind[i]+k]);505end = beg-1 + rellen[i];506ifront = iback = knr;507508/* Forward scan, leaving ifront set to coset at left of leftmost hole in509relator or to the last coset in the relator if no hole. */510511for (fwd = beg; fwd <= end; fwd++)512{513if ((l = CT(ifront, *fwd)) > 0)514{ ifront = l; }515else516{ break; }517}518519/* If the scan completed, then l = ifront & iback = cos, and we'll fall520right through and check for a coincidence (i.e., has ifront cycled back521to cos or not?). Else, there's a hole & a backward scan is required. */522523if (l == 0)524{525for (bwd = end; bwd >= fwd; bwd--)526{527m = *bwd;528mi = invcol[m];529530if ((l = CT(iback, mi)) > 0)531{ iback = l; }532else /* Scan stalled */533{534if (bwd == fwd)535{536/* The backward scan has only one gap, so note the deduction to537complete the cycle & prime for coincidence check. */538539CT(iback, mi) = ifront;540if (saved)541{ SAVED(iback, mi); }542543if (CT(ifront, m) > 0)544{ ifront = CT(ifront, m); }545else546{547CT(ifront, m) = iback;548ifront = iback;549}550551INCR(rddedn);552}553else /* Need to define a new coset */554{555/* Note that, if m is an involution, and occurs next to itself,556then after the first defn, the remainder of the string of m's557will close. Note that if m^2 = 1 & m is _not_ being treated as558an involution, then `removing' it is a Tietze transformation, not559a free reduction! */560561if (nextdf > maxrow) /* Overflow */562{ return(0); }563564NEXTC(n); /* Making a definition ... */565566CT(iback,mi) = n;567CT(n,m) = iback;568if (saved)569{ SAVED(iback,mi); }570571iback = n; /* Advance to next spot */572573INCR(rddefn);574575if (msgctrl && --msgnext == 0)576{577msgnext = msgincr;578ETINT;579fprintf(fop, "RD: a=%d r=%d h=%d n=%d;",580nalive, knr, knh, nextdf);581MSGMID;582fprintf(fop, " m=%d t=%d\n", maxcos, totcos);583BTINT;584}585}586}587}588}589590/* If we get here, the scan has been completed. Check to see if we've591found a pair of coincident cosets. Recall that _coinc (if it does not592return >0) is guaranteed _not_ to change knc/knh, although it may render593them redundant. */594595if (ifront != iback)596{597INCR(rdcoinc);598if ((l = al0_coinc(ifront,iback,saved)) > 0)599{ return(l); }600if (COL1(knr) < 0)601{ goto do_next; } /* knr now redundant */602}603604/* --> restore indent */605606}607}608609/* All relators close at this coset, any row-filling to do? Only610(formally) necessary if some g/G does _not_ appear in any relator,611but it's usually a good thing to do. */612613if (fillr)614{615for (i = 1; i <= ncol; i++)616{617if (CT(knr,i) == 0)618{619if (nextdf > maxrow) /* Overflow */620{ return(0); }621622NEXTC(k); /* Make definition */623CT(knr,i) = k;624CT(k,invcol[i]) = knr;625if (saved)626{ SAVED(knr,i); }627628INCR(rdfill);629630if (msgctrl && --msgnext == 0)631{632msgnext = msgincr;633ETINT;634fprintf(fop, "RF: a=%d r=%d h=%d n=%d;",635nalive, knr, knh, nextdf);636MSGMID;637fprintf(fop, " m=%d t=%d\n", maxcos, totcos);638BTINT;639}640}641}642}643644/* Row knr is fully scanned (or redundant), so we adjust knr up,645jumping over any redundancies & checking to see if we've finished. We646have also used up one of our allowed rows, if there's a limit. */647648do_next: /* from al0_coinc(): knr redundant */649650do651{ knr++; }652while (knr < nextdf && COL1(knr) < 0);653654if (knr == nextdf)655{ return(nalive); }656657if (cnt > 0)658{ cnt--; }659}660661return(-1); /* `normal' termination */662}663664/******************************************************************665static int al0_cdefn(int cnt)666667Repeatedly process any outstanding deductions and make definitions668until: we get a finite result (return > 0), we get an overflow669(return 0), or we've defined cnt new cosets (return -1). If cnt670is zero then we make no definitions, simply clearing the deduction671stack. If cnt < 0 there's no limit on the number of definitions.672******************************************************************/673674static int al0_cdefn(int cnt)675{676int icol, rcol, irow, ires, k, col, pdqr, pdqc;677int first, last, i, ifront, iback, l, m, mi;678int *beg, *end, *fwd, *bwd;679Logic fi;680681INCR(xcdefn);682683while(TRUE)684{685/* Process all outstanding deductions on the stack */686687while (topded >= 0)688{689INCR(cddproc);690691irow = dedrow[topded];692icol = dedcol[topded--];693if (COL1(irow) < 0)694{695INCR(cdddedn);696continue; /* coset has become redundant */697}698else699{700ires = CT(irow,icol);701rcol = invcol[icol];702}703704fi = TRUE; /* first pass through */705706proc_ded: /* entry point for second pass through */707708if ((first = edpbeg[icol]) >= 0)709{710last = edpend[icol];711for (i = first; i <= last; i += 2)712{713beg = &(relators[edp[i]]);714end = beg + edp[i+1]-1;715716/* <-- cancel indent */717718/* We scan this e.d.p. against irow. We don't need to scan the first719position, since we _know_ it must be ok. We have to set l, in case the720relator has length precisely one! */721722ifront = l = ires;723iback = irow;724725/* Forward scan, leaving ifront set to coset at left of leftmost hole in726relator or to the last coset in the relator if no hole. */727728for (fwd = beg+1; fwd <= end; fwd++)729{730if ((l = CT(ifront, *fwd)) > 0)731{ ifront = l; }732else733{ break; }734}735736/* If the scan completed, ifront = l > 0 & iback = irow, and we'll fall737right through and check for a coincidence (i.e., has ifront cycled back738to irow or not?). Else, there's a hole & a backward scan is required. */739740if (l == 0)741{742for (bwd = end; bwd >= fwd; bwd--)743{744m = *bwd;745mi = invcol[m];746747if ((l = CT(iback, mi)) > 0)748{ iback = l; }749else /* Scan stalled */750{751if (bwd == fwd)752{753/* The backward scan has only one gap, so note the deduction to754complete the cycle. */755756CT(iback, mi) = ifront;757CT(ifront, m) = iback;758SAVED(iback, mi);759760INCR(cddedn);761}762else if (bwd == fwd + 1) /* gap of length = 1 */763{764INCR(cdgap);765766/* In pdefn = 1 or 2 mode make definition immediately, if fill-767factor permits, there's space & it's allowed. If not, do768nothing. Note that we can handle the deduction from this769definition at this stage, or not (it'll come out in a later pass770through the loop), depending as pdefn = 1 or 2. In general,771these strategies blow out the count of total cosets, although772making definitions immediately is quicker than storing them on773the pdq & making them later, so pdefn=1/2 has a higher774`throughput'; whether this compensates for the larger totcos775figure is moot! */776777switch(pdefn)778{779case 1:780if (cnt != 0 && nextdf <= maxrow &&781(float)(knh-1)*ffactor >= (float)(nextdf-1) )782{783NEXTC(k);784CT(iback, mi) = k;785CT(k, m) = iback;786SAVED(iback, mi);787788if (cnt > 0)789{ cnt--; } /* used an `allowed' definition */790INCR(cdidefn);791792if (msgctrl && --msgnext == 0)793{794msgnext = msgincr;795ETINT;796fprintf(fop, "CG: a=%d r=%d h=%d n=%d;",797nalive, knr, knh, nextdf);798MSGMID;799fprintf(fop, " m=%d t=%d\n", maxcos, totcos);800BTINT;801}802}803break;804805case 2:806if (cnt != 0 && nextdf <= maxrow &&807(float)(knh-1)*ffactor >= (float)(nextdf-1) )808{809NEXTC(k);810CT(iback, mi) = k;811CT(k, m) = iback;812SAVED(iback, mi);813814if (cnt > 0)815{ cnt--; } /* used an `allowed' definition */816INCR(cdidefn);817818CT(ifront,*fwd) = k;819CT(k,invcol[*fwd]) = ifront;820SAVED(ifront,*fwd);821822INCR(cdidedn);823824if (msgctrl && --msgnext == 0)825{826msgnext = msgincr;827ETINT;828fprintf(fop, "CG: a=%d r=%d h=%d n=%d;",829nalive, knr, knh, nextdf);830MSGMID;831fprintf(fop, " m=%d t=%d\n", maxcos, totcos);832BTINT;833}834}835break;836837case 3: /* store definition on pdq */838pdqrow[botpd] = iback;839pdqcol[botpd] = mi;840INCR(cdpdl);841if ((botpd = NEXTPD(botpd)) == toppd)842{843toppd = NEXTPD(toppd);844INCR(cdpof);845}846break;847}848}849850iback = ifront; /* prevents a false coincidence */851break;852}853}854}855856/* At this stage, if ifront != iback, then either the initial forward857scan did not cycle back to irow, or a backward scan produced a mismatch;858in either case, we have found a coincidence. In all other cases ifront =859iback has been enforced, to prevent problems. */860861if (iback != ifront)862{863/* We do _not_ return an index at this stage if _coinc() returns a +ve864value, since there may still be deductions to process (which might865_decrease_ nalive). We do, however, detect if the current rows have866become redundant. Currently, the only finite value returned by867_coinc() is 1, on a total collapse. This clears the dedn stack, so868we'll drop out of the while(topded>=1) loop immediately & then drop869out of this function with an index of 1. */870871INCR(cdcoinc);872al0_coinc(ifront,iback,TRUE);873if (COL1(irow) < 0 || COL1(ires) < 0)874{ goto next_ded; }875}876877/* --> restore indent */878879}880}881882/* Do we have to do a second pass? */883884if (fi && (irow != ires || icol != rcol))885{886SWAP(irow,ires);887SWAP(icol,rcol);888fi = FALSE;889goto proc_ded;890}891892/* End of processing this deduction, loop back to next deduction. We893also jump here if current deduction becomes redundant. */894895next_ded:896;897898#ifdef AL0_DD899if (msgctrl && --msgnext == 0)900{901msgnext = msgincr;902ETINT;903fprintf(fop, "DD: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);904MSGMID;905fprintf(fop, " d=%d\n", topded+1);906BTINT;907}908#endif909}910911/* Find next empty position (& maybe finish). */912913for ( ; knh < nextdf; knh++)914{915if (COL1(knh) >= 0)916{917for (icol = 1; icol <= ncol; icol++)918{919if (CT(knh, icol) == 0)920{ goto hfill; }921}922}923}924return(nalive); /* coset table is complete */925926/* Try to fill the next hole in the table */927928hfill:929930if (cnt == 0) /* `normal' termination, since */931{ return(-1); } /* done all requested definitions */932else933{934/* Do we have space to make a definition? If not, return overflow.935If yes, prime the next sequential position & get its row number. */936937if (nextdf > maxrow)938{ return(0); } /* unable to make definition */939NEXTC(k); /* ready for definition ... */940941/* We try to make a preferred definition, if possible. If we do,942fi is set TRUE. */943944fi = FALSE;945if ( pdefn == 3 && toppd != botpd946&& (float)(knh-1)*ffactor >= (float)(nextdf-1) )947{948pdqr = pdqrow[toppd];949pdqc = pdqcol[toppd];950while (COL1(pdqr) < 0 || CT(pdqr,pdqc) != 0)951{952INCR(cdpdead);953if ((toppd = NEXTPD(toppd)) == botpd)954{ break; }955pdqr = pdqrow[toppd];956pdqc = pdqcol[toppd];957}958959if (toppd != botpd)960{961toppd = NEXTPD(toppd);962CT(pdqr,pdqc) = k;963CT(k,invcol[pdqc]) = pdqr;964SAVED(pdqr,pdqc);965966fi = TRUE;967INCR(cdpdefn);968969if (msgctrl && --msgnext == 0)970{971msgnext = msgincr;972ETINT;973fprintf(fop, "CP: a=%d r=%d h=%d n=%d;",974nalive, knr, knh, nextdf);975MSGMID;976fprintf(fop, " m=%d t=%d\n", maxcos, totcos);977BTINT;978}979}980}981982/* If no preferred definition made, fill next hole. */983984if (!fi)985{986CT(knh,icol) = k;987CT(k,invcol[icol]) = knh;988SAVED(knh,icol);989990INCR(cddefn);991992if (msgctrl && --msgnext == 0)993{994msgnext = msgincr;995ETINT;996fprintf(fop, "CD: a=%d r=%d h=%d n=%d;",997nalive, knr, knh, nextdf);998MSGMID;999fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1000BTINT;1001}1002}10031004if (cnt > 0) /* keep track, if there's a limit */1005{ cnt--; }1006}1007}1008}10091010/******************************************************************1011static int al0_rpefn(int cnt, Logic fill)1012******************************************************************/10131014#include "enum01.c"10151016/******************************************************************1017Pull in the state machine.1018******************************************************************/10191020#include "enum00.c"10211022/******************************************************************1023int al0_enum(int mode, int style)10241025mode 0 : start enumeration (from row 1 of zeroed table)10261 : continue enumeration (from current row of current table)10272 : redo enumeration (from row 1 of current table)10281029style 0 : R/C HLT until overflow, then CR-style10301 : R* R-style + dedn stacking/processing10312 : Cr 1 pass Felsch, 1 pass HLT, then C-style10323 : reserved Level 1: C* (?!)10334 : reserved Level 1: defaulted R/C10345 : C Felsch strategy10356 : Rc 1 pass HLT, 1 pass Felsch, then R-style10367 : R HLT strategy10378 : CR alternate Felsch & HLT passes10381039We can `start' at any time. We can `redo' at any time provided1040that any changes to the presentation are confined to _adding_1041group relators or subgroup generators. We can `continue' only if1042we have made _no_ changes to the presentation (& even if we already1043have a finite index). The rfactor/cfactor parameters must be set1044correctly (ie, >0) for the `style' of this call; they can be 0 (or1045even <0), but this may cause weirdness (although some intriguing1046things become possible).10471048return >1 : non-trivial finite index10491 : index of 1 (? collapse in coincidence processing)10500 : overflow1051-256 : incomplete table (ie, unfilled positions)1052-257 : hole limit exceeded1053-258 : time limit exceeded1054-259 : iteration (loops) limit exceeded1055-260 : overflow during SG phase1056-512 : disallowed mode1057-513 : disallowed style1058-514 : disallowed mode/style combination (not used yet))1059-4096 : invalid machine state (aka reality failure)1060-4097 : invalid finite result (aka reality failure)1061******************************************************************/10621063int al0_enum(int mode, int style)1064{1065int state, action, result; /* The current state, action & result. */1066Logic isave; /* Save definitions/deductions on stack? */1067static Logic rhfree; /* Table guaranteed hole-free (R-style)? */1068static Logic cdapp; /* All definitions applied (C-style)? */1069int i,j,k; /* temp ints / indices */1070int *pj, *pk; /* temp pointers */1071Logic li; /* temp booleans */10721073/* Start up the timing for this call. Prime the message counter (if1074required), initialise the stats package (if macro is defined), and zero1075the loop count. */10761077totaltime = 0.0;1078begintime = al0_clock();1079if (msgctrl)1080{ msgnext = msgincr; }1081STATINIT;1082lcount = 0;10831084/* Check mode, style, and their combination. */10851086if (mode < 0 || mode > 2)1087{1088result = -512;1089goto tail_tail;1090}1091if (style < 0 || style > 8 || style == 3 || style == 4)1092{1093result = -513;1094goto tail_tail;1095}10961097/* Do the appropriate setup for the requested mode. Note that we _never_1098preserve pd's between calls, and there are _never_ outstanding coincs1099at a call's exit (so we don't actually need to zero chead/ctail, but we1100do anyway!). We may, or may not, preserve deduction stack, entries in1101the table and the various `progress' counters. */11021103toppd = botpd = 0;1104chead = ctail = 0;11051106switch(mode)1107{1108case 0: /* start; ie, a new run */11091110topded = -1;1111disded = FALSE;11121113for (i = 1; i <= ncol; i++)1114{ CT(1, i) = 0; }11151116nalive = maxcos = totcos = 1;1117knr = knh = 1;1118nextdf = 2;11191120sgdone = FALSE; /* SG not (successfully) run yet */1121rhfree = cdapp = TRUE; /* prime for this new run */11221123break;11241125case 1: /* continue */11261127;11281129break;11301131case 2: /* redo */11321133topded = -1;1134disded = FALSE;11351136knr = knh = 1;11371138sgdone = FALSE;11391140break;1141}11421143/* The static variable rhfree is primed to true at the start of every run1144(ie, start mode), and retains its value across a sequence of continue &1145redo commands until the next start. Any time we could _potentially_ do1146any R-style applying without filling rows, we toggle it to false. This1147indicates that the table _may_ contain holes, and that the al0_upknh()1148routine may need to be called before a finite index (due to knr = nextdf)1149is returned. Any code anywhere which could cause empty table slots1150should take care to ensure that rhfree is false. Since rhfree is only1151invoked when checking a finite result due to knr = nextdf, its value if1152we get a result due to knh=nextdf is of no concern (here, the table is1153hole-free, since that's what knh means!).11541155Instead of trying to be clever, and keeping a close watch on what the1156value of this should be at each point, we simply reset it at the start of1157any call(s) where the rfill control parameter is false. The cost of1158running _upknh() is no more than that of row-filling (although it's1159concentrated in one `lump'), since all table positions are checked in1160both cases. In fact, it will usually be less, since we can start the1161check at knh, we need not check rows that have become redundant, and we1162make no definitions. Note that, even if row-filling is not needed (to1163obtain a finite index), it may still be beneficial to turn it on, since1164it may alter the definition sequence. */11651166if (!rfill)1167{ rhfree = FALSE; }11681169/* Do the appropriate setup for the requested style. Our main concern1170is whether or not to stack defns/dedns (isave flag) so that these can be1171tested against all edp, for C-style enumerations. We also have to track1172whether or not we have done this over the course of an entire run; we use1173the cdapp flag for this. This flag is similar in concept to the rhfree1174one, but is more difficult to manage, since it is `more expensive' to get1175it `wrong'. Furthermore, saving & applying dedns is a 3-stage process,1176and cdapp only tracks the first step.11771178cdapp is static, and is primed to true. Any time we _may_ make any table1179entries _without_ stacking them, we toggle it to false. Whether or not1180the stacking (call to SAVED()) was successful is monitored by the global1181disded flag. Whether or not all the stacked dedns have been processed is1182determined by the stack size (the global topded). If knh=nextdf and all1183three stages were successful (ie, cdapp=TRUE & disded=FALSE & topded==-1)1184then the result is valid. If not, then the actual index may be smaller1185than the `current' one (ie, nalive). Since our table is guaranteed hole-1186free at this stage, the quickest check is to run an R-style scan (with1187definitions & deduction stacking both off!) to move knr up to nextdf,1188perhaps finding some coincs along the way; this RA phase is the default1189action.11901191The settings below prime isave & cdapp for the styles. However, finer1192control is needed since, for example, a (successful) CL phase forces1193cdapp back to true (provided further dedns _will_ be stacked (ie, isave1194is true)). We use the switch at the end of the state machine's main1195loop to do this. Note that we must be careful, since we can exit at any1196time and we must ensure that the status is valid for any continues or1197redos. We err on the side of caution, so the RA phase may be done when1198it is not (formally) required.11991200Note that in some styles we don't save deductions initially, since we do1201a C-style table lookahead at the point where we switch from R-style to1202C-style (which effectively forces cdapp to true). (We could also insist1203that _all_ dedns _are_ applied, and do a C-style lookahead at any point1204where we detect `missed' dedns.) Of course, if the dedn stack is large1205enough, then we'll never lose dedn's; but we could end up having to1206process _very_ large dedn stacks, which can be expensive. */12071208switch(style)1209{1210case 0:1211isave = FALSE;1212cdapp = FALSE;1213break;12141215case 1:1216isave = TRUE;1217break;12181219case 2:1220isave = TRUE;1221break;12221223case 5:1224isave = TRUE;1225break;12261227case 6:1228isave = FALSE;1229cdapp = FALSE;1230break;12311232case 7:1233isave = FALSE;1234cdapp = FALSE;1235break;12361237case 8:1238isave = TRUE;1239break;1240}12411242/* Combine the style with the mode into the machine's starting state.1243Prime machine with `dummy'/`null' action & `success' result. */12441245state = 1 + 9*mode + style;12461247action = 0;1248result = -1;12491250/* THE MACHINE ... */12511252while (TRUE)1253{1254/* lcount tracks which pass through the machine's loop this is. Then1255use result of last action to get next state & action. */12561257lcount++;12581259/* DEBUG/TEST/TRACE (DTT) code. Monitors the state machine. */1260/*1261fprintf(fop, "DTT: lcount=%d; state=%d action=%d result=%d",1262lcount, state, action, result);1263*/12641265action = al0_act[state][-result];1266state = al0_st[state][-result];12671268/* Warning: DTT code (see above) */1269/*1270fprintf(fop, " --> state=%d action=%d\n", state, action);1271*/12721273switch(action)1274{12751276/* <-- cancel indent */12771278/* The null action; allows timing tests, progress messages, etc. */12791280case 0:1281result = -1;1282break;12831284/* Make some R-style definitions. al0_rdefn() can return -1 (`nothing'1285happened), 0 (unable to make definition), or >0 (finite result). Note1286that _all_ finite `index' return values are `filtered' through the check1287phase (action #6), to prevent `problems'. */12881289case 1:12901291if ((result = al0_rdefn(rfactor, rfill, isave)) > 0)1292{ result = -2; }12931294break;12951296/* Perform lookahead, in R-style _only_, if enabled. This lookahead is1297used when we run out of table space, and it could allow us to continue1298_without_ running a compaction. However, we elect not to detect this1299state of affairs in the current version. Instead, we'll _always_ try to1300compact, and we'll check after doing that whether or not there's any1301space available in the table (however it was obtained!). Note that1302lookahead (& any coincidence processing) does _not_ alter nextdf or knr/1303knh (except in the collapse to 1 case, of course), although it may render1304them redundant. Since this is a _lookahead_ only, there is never any1305need to stack deductions. We don't try to trap an invalid lahead value.1306If we don't recognise it, we just quietly do nothing.13071308Note that we can be as `sloppy' as we wish, in the sense that all we1309require is one or more coincs to free up some table space. The current1310options all look only for immediate consequences of the current table,1311and don't worry about consequent consequences. There are a great variety1312of other ways to do lookahead. For example: we could repeatedly run1313_rl() until there's no further improvement; or we could bail out early,1314after a burst of `significant' progress or if we're achieving1315`nothing'. */13161317case 2:13181319switch(lahead)1320{1321case 1:1322result = al0_rl(knr, nextdf-1, FALSE);1323if (msgctrl)1324{1325msgnext = msgincr; /* start new count */1326ETINT;1327fprintf(fop, "L1: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1328MSGMID;1329fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1330BTINT;1331}1332break;1333case 2:1334result = al0_cl(1, nextdf-1, FALSE);1335if (msgctrl)1336{1337msgnext = msgincr;1338ETINT;1339fprintf(fop, "L2: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1340MSGMID;1341fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1342BTINT;1343}1344break;1345case 3:1346result = al0_rl(1, nextdf-1, FALSE);1347if (msgctrl)1348{1349msgnext = msgincr;1350ETINT;1351fprintf(fop, "L3: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1352MSGMID;1353fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1354BTINT;1355}1356break;1357case 4:1358result = al0_cl(knr, nextdf-1, FALSE);1359if (msgctrl)1360{1361msgnext = msgincr;1362ETINT;1363fprintf(fop, "L4: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1364MSGMID;1365fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1366BTINT;1367}1368break;1369default:1370result = -1;1371break;1372}13731374if (result > 0)1375{ result = -2; }13761377break;13781379/* Perform compaction (any style) if it's allowed & then check whether1380the table has any space left. If so, then continue, else return1381overflow. Note that compaction does _not_ alter nalive, but may change1382(reduce) knr/knh/nextdf. It makes `free' space _available_, but it does1383not _create_ it; coincidences (normal, or in lookahead) do that. */13841385case 3:13861387if (nalive >= maxrow)1388{1389result = 0;1390goto tail_tail;1391}1392else if ( (double)(nextdf-1 - nalive)/(double)(nextdf-1)1393>= (double)comppc/100.0 )1394{1395/* DTT: how expensive is compaction? */1396/*1397if (msgctrl)1398{1399msgnext = msgincr;1400ETINT;1401fprintf(fop, "co: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1402MSGMID;1403fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1404BTINT;1405}1406*/1407al0_compact();1408if (msgctrl)1409{1410msgnext = msgincr;1411ETINT;1412fprintf(fop, "CO: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1413MSGMID;1414fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1415BTINT;1416}1417}14181419if (nextdf <= maxrow)1420{ result = -1; }1421else1422{1423result = 0;1424goto tail_tail;1425}14261427break;14281429/* Do some C-style definitions / deduction processing. al0_cdefn() can1430return -1 (`nothing' happened), 0 (unable to make definition), or >01431(finite result - potential index, needs checking). */14321433case 4:14341435if ((result = al0_cdefn(cfactor)) > 0)1436{ result = -2; }14371438break;14391440/* Do a C-style complete table lookahead. This is run when we're1441switching styles from R- to C-style, or when we're `starting' C-style1442with an already existing table. Since we maybe haven't being processing1443definitions, we need to run through the entire table. We treat each1444table entry as a deduction and stack any new deductions. A subsequent1445C-style defn/dedn pass will clear the stack, as usual; we can now enter1446C-style, and be confident of any C-style result.14471448Actually, calling this lookahead is a misnomer. It more correctly might1449be thought of as either a `check' (when we have a finite result but1450cannot guarantee that all definitions have been processed, or when we1451call the enumerator in the redo mode) or a `prime' (when we're switching1452to C-style) phase. */14531454case 5:14551456if ((result = al0_cl(1, nextdf-1, TRUE)) > 0)1457{ result = -2; }1458if (msgctrl)1459{1460msgnext = msgincr;1461ETINT;1462fprintf(fop, "CL: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1463MSGMID;1464fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1465BTINT;1466}14671468break;14691470/* We have a finite result; triggered by knr=nextdf, knh=nextdf, or a1471collapse to 1 in coinc processing. Check that it's a valid index; it may1472be a multiple, or the table may have holes. If knr=nextdf, then all1473relators close against all cosets, so we need only check whether or not1474the table has any holes. If knh=nextdf, then the table is hole-free, so1475we need to check that all table entries have been scanned in all edp.1476Note that we have to check for a `clean' C-style termination _before_ we1477may bump knh; this is an artifact of the overloading of knh's meaning. */14781479case 6:14801481if (knr == nextdf && rhfree)1482{ ; } /* ok, fall through */1483else if (knh == nextdf && cdapp && !disded && topded < 0)1484{ ; } /* ok, fall through */1485else if (knr == nextdf)1486{1487al0_upknh(); /* check for holes ... */1488if (msgctrl)1489{1490msgnext = msgincr;1491ETINT;1492fprintf(fop, "UH: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1493MSGMID;1494fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1495BTINT;1496}1497if (knh < nextdf) /* ... table is incomplete */1498{1499result = -256;1500goto tail_tail;1501}1502}1503else if (knh == nextdf)1504{1505/* Apply all remaining cosets. Note that knh=nextdf, so there are no1506holes & no defns will (can!) be made. Since we are only interested in1507moving knr up to nextdf (perhaps finding coincs), we turn mendel off;1508if it's on (& left on), it can cause a dramatic slow-down. */15091510li = mendel;1511mendel = FALSE;1512al0_rdefn(-1,FALSE,FALSE);1513mendel = li;15141515if (msgctrl)1516{1517msgnext = msgincr;1518ETINT;1519fprintf(fop, "RA: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1520MSGMID;1521fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1522BTINT;1523}1524}1525else1526{ /* fatal error (ie, can't happen!) */1527result = -4097;1528goto tail_tail;1529}15301531result = nalive;1532goto tail_tail;15331534break; /* not really needed! */15351536/* If start or redo, scan & close the subgroup generators on coset #1.1537Note that we can get coincidences, or collapses, or overflows here. We1538treat an overflow as fatal, and return a special value (-260) to alert1539the caller to the fact that the subgroup generators have not been fully1540processed (so we _must_ (re)start, we can't continue). Note that knr =1541knh = 1 here, and they are _not_ changed (we do no scanning against the1542relators, so they can't go up, and coset 1 is never redundant). Thus the1543only finite index we can get is a collapse to 1, and this is a valid1544result.15451546Note that closing subgroup generators against coset 1 is done R-style, in1547that we (maybe) stack up definitions/deductions for later action, and1548make as many definitions as required to (immediately) fill any empty1549relator table positions. If the enumeration is a (pure) C-style one, we1550should process each definition (ie, stacked deduction) _immediately_,1551since we should only make definitions if there's nothing else we can do.1552For the moment, we don't worry about his `complication'.15531554As this phase _must_ be successfully completed before a continue is1555allowed, and it need not be the 1st phase (it can be the 2nd in redo), a1556time/hole/loop limit could cause an early return. So we make sure the1557sgdone flag is correctly (re)set at all times. */15581559case 7:15601561if (nsgpg > 0)1562{1563for (i = 1; i <= nsgpg; i++)1564{1565pj = &(subggen[subgindex[i]]);1566pk = pj-1 + subglength[i];15671568if ((result = al0_apply(1,pj,pk,TRUE,isave)) >= 0)1569{ break; }1570}15711572if (msgctrl)1573{1574msgnext = msgincr;1575ETINT;1576fprintf(fop, "SG: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1577MSGMID;1578fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1579BTINT;1580}15811582sgdone = TRUE;1583if (result == 0)1584{1585result = -260;1586sgdone = FALSE;1587goto tail_tail;1588}1589else if (result > 0)1590{ result = -2; }1591}1592else1593{1594result = -1; /* `default' result */1595sgdone = TRUE; /* ok, since nothing to do! */1596}15971598break;15991600/* If start or redo (modes 0/2) and in an appropriate style (ie, 1st step1601will be a C-style scan), and requested (nrinsgp > 0), then scan & close1602the first nrinsgp group relators against coset 1. Similar comments to1603those for the subgroup generators apply here, although an overflow does1604_not_ force a restart here. */16051606case 8:16071608if (nrinsgp > 0)1609{1610for (i = 1; i <= nrinsgp; i++)1611{1612j = (mendel ? rellen[i]/relexp[i] : 1);1613for (k = 0; k < j; k++)1614{1615pj = &(relators[relind[i]+k]);1616pk = pj-1 + rellen[i];16171618if ((result = al0_apply(1,pj,pk,TRUE,isave)) >= 0)1619{ break; }1620}16211622if (result >= 0)1623{ break; }1624}16251626if (msgctrl)1627{1628msgnext = msgincr;1629ETINT;1630fprintf(fop, "RS: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);1631MSGMID;1632fprintf(fop, " m=%d t=%d\n", maxcos, totcos);1633BTINT;1634}16351636if (result > 0)1637{ result = -2; }1638}1639else1640{ result = -1; } /* `default' result */16411642break;16431644/* Do some R*-style definitions / deduction processing. al0_rpefn() can1645return -1 (`nothing' happened), 0 (unable to make definition), or >01646(finite result - potential index, needs checking). Note the row-filling1647argument and the fact that we don't use (need?) isave, since dedn1648stacking is mandatory here. */16491650case 9:16511652if ((result = al0_rpefn(rfactor, rfill)) > 0)1653{ result = -2; }16541655break;16561657/* If we get here, something's a touch awry. */16581659default:1660result = -4096;1661goto tail_tail;16621663/* --> restore indent */16641665} /* end of "switch(action)" */16661667/* At this point, we have just completed action in state, and are about1668to `leave' state via one of its exit paths (selected by the (state,1669result) pair). Now is the time to perform any action specific to this1670point. Note that the checks for the various limits (times, holes, ...)1671are done _after_ this, so we're guaranteed that the (updated) status1672will be correct on any `early' exit. */16731674switch(state)1675{1676case 32:1677if (result == -1)1678{ cdapp = TRUE; }1679break;1680case 38:1681if (result == -1)1682{ cdapp = TRUE; }1683break;1684case 45:1685if (result == 0)1686{ isave = TRUE; }1687break;1688case 46:1689if (result == -1)1690{ cdapp = TRUE; }1691break;1692case 47:1693if (result == -1)1694{ cdapp = TRUE; }1695break;1696case 55:1697if (result == -1)1698{ cdapp = TRUE; }1699break;1700case 56:1701if (result == -1)1702{ cdapp = TRUE; }1703break;1704case 58:1705if (result == -1 || result == 0)1706{ cdapp = FALSE; }1707case 59:1708if (result == -1)1709{ cdapp = TRUE; }1710break;1711}17121713/* Only calculate % holes if requested, since it's expensive! We only1714treat the value as significant if we've actually defined some cosets1715other than #1! We ignore the case where nalive=1 and not all #1's row1716entries are 0 (ie, some, but not necessarily all, are 1 instead). */17171718if (hlimit >= 0 && nalive > 1)1719{1720if (al0_nholes() >= (double)hlimit)1721{1722result = -257;1723break;1724}1725}17261727/* We have to correctly find the total accumulated time, without1728disturbing any messaging (which must always print the elapsed time1729since the last message). So we _can't_ use the ETINT/BTINT macros. */17301731if (tlimit >= 0)1732{1733if ((totaltime + al0_diff(begintime,al0_clock())) >= (double)tlimit)1734{1735result = -258;1736break;1737}1738}17391740/* Any loop limit in force? */17411742if (llimit > 0 && lcount >= llimit)1743{1744result = -259;1745break;1746}17471748} /* end of "while(TRUE)" */17491750/* We've either jumped here (finite result, overflow, error), or we've1751broken out the main loop (time / holes / iterations limit). We simply1752update the total time for this call & return the `status'. */17531754tail_tail:17551756endtime = al0_clock();1757totaltime += al0_diff(begintime,endtime);17581759return(result);1760}1761176217631764