1
2 /**************************************************************************
3
4 util0.c
5 Colin Ramsay (cram@itee.uq.edu.au)
6 20 Dec 00
7
8 ADVANCED COSET ENUMERATOR, Version 3.001
9
10 Copyright 2000
11 Centre for Discrete Mathematics and Computing,
12 Department of Mathematics and
13 Department of Computer Science & Electrical Engineering,
14 The University of Queensland, QLD 4072.
15 (http://staff.itee.uq.edu.au/havas)
16
17 These are some utilities for Level 0 of ACE.
18
19 **************************************************************************/
20
21 #include "al0.h"
22
23 /******************************************************************
24 We seem to need sys/types.h & time.h (for the system call time()).
25 On other flavours of Unix, we might need sys/time.h.
26 ******************************************************************/
27
28 #include <sys/types.h>
29 #include <time.h>
30
31 /******************************************************************
32 char *al0_date(void)
33
34 Gets the system date/time, and converts it to ASCII string. Note
35 that this includes a trailing '\n'.
36 ******************************************************************/
37
al0_date(void)38 char *al0_date(void)
39 {
40 time_t t = time(NULL);
41 return ctime(&t);
42 }
43
44 /******************************************************************
45 double al0_clock(void)
46
47 clock() returns the actual cpu time used, in seconds, since this
48 process started. It's equivalent to the `user' time in the `time'
49 system command. Type clock_t is usually defined as a (signed)
50 long, but seems to actually be a 32-bit unsigned - we try our best
51 to preserve all information over a variety of machines! Note that
52 64-bit machines may sign extend, hence the truncation.
53 CLOCKS_PER_SEC (usually 1000000, but may be 100 on a PC) converts
54 clock() to seconds. Note that, even if CLOCKS_PER_SECOND > 100,
55 resolution may only be 10mS (i.e., 100Hz system clock).
56 ******************************************************************/
57
al0_clock(void)58 double al0_clock(void)
59 {
60 unsigned long ulc = 0xffffffffUL & (unsigned long)clock();
61
62 return (double)ulc/(double)CLOCKS_PER_SEC;
63 }
64
65 /******************************************************************
66 double al0_diff(double c1, double c2)
67
68 We assume that c1/c2 are values from al0_clock(). This routine
69 finds the difference between two times, by assuming that either 0
70 or 1 `overflow' has taken place. double's are used for all timing
71 to allow (long) times to be properly processed. Provided that the
72 run is `short' (w.r.t. to the normal rollover interval of 71m35s)
73 or that progress messages are output `frequently', then the
74 difference will be correct. On long runs with few messages, then
75 the difference may be incorrect.
76 ******************************************************************/
77
78
al0_diff(double c1,double c2)79 double al0_diff(double c1, double c2)
80 {
81 double clkroll = ((double)65536*(double)65536)/(double)CLOCKS_PER_SEC;
82
83 if (c2 >= c1)
84 { return (c2-c1); }
85 else
86 { return (clkroll - c1 + c2); }
87 }
88
89 /******************************************************************
90 void al0_init(void)
91
92 One-off initialisation of the Level 0 stuff. Ensures a valid
93 initial state, and sets defaults (default setting is roughly
94 equivalent to the "def" option of Level 2). Does _not_ allocate /
95 free memory, so it's up to the user (in practice, usually the Level
96 1 wrapper routines) to make sure memory's allocated and to properly
97 free it to prevent memory leakage. It's not really necessary to
98 set _everything_ here, but we do anyway, since we adhere to the
99 P^3 Principle (ie, paranoia prevents problems)!
100 ******************************************************************/
101
al0_init(void)102 void al0_init(void)
103 {
104 fop = stdout;
105 fip = stdin;
106 setvbuf(stdout, NULL, _IOLBF, 0); /* line buffer o/p */
107
108 begintime = endtime = deltatime = totaltime = 0.0;
109 msgctrl = msghol = FALSE;
110 msgincr = msgnext = -1;
111
112 mendel = FALSE;
113 rfill = TRUE;
114 pcomp = FALSE;
115
116 maxrow = 0;
117 rfactor = 200;
118 cfactor = 1000;
119 comppc = 10;
120 nrinsgp = 0;
121 lahead = 1;
122
123 tlimit = -1;
124 hlimit = -1;
125 llimit = lcount = 0;
126
127 nalive = maxcos = totcos = 1;
128
129 chead = ctail = 0;
130
131 pdefn = pdsiz = 0;
132 ffactor = 0.0;
133 pdqcol = pdqrow = NULL;
134 toppd = botpd = 0;
135
136 dedsiz = 0;
137 dedrow = dedcol = NULL;
138 topded = -1;
139 dedmode = 0;
140 disded = FALSE;
141
142 edp = edpbeg = edpend = NULL;
143
144 ncol = 0;
145 colptr = NULL;
146 col1ptr = col2ptr = NULL;
147 invcol = NULL;
148
149 ndrel = 0;
150 relind = relexp = rellen = relators = NULL;
151
152 nsgpg = 0;
153 subggen = subgindex = subglength = NULL;
154 sgdone = FALSE;
155
156 knr = knh = 1;
157 nextdf = 2;
158 }
159
160 /******************************************************************
161 Logic al0_compact(void)
162
163 Remove unused rows from the coset table, by closing up all used
164 rows to the front. (This is _not_ the same as putting the table
165 into its canonic form!) To maintain data-structure consistency,
166 the pdq is cleared & any stored deductions/coincidences should be
167 discarded. The pdq entries don't matter, but throwing away
168 unprocessed deductions or coincidences is _not_ a good thing. It
169 is the _caller's_ responsibility to ensure that this routine isn't
170 called when there are outstanding deductions/coincidences or, if
171 it is, that `appropriate' action is taken. We return TRUE if we
172 actually did any compaction, else FALSE.
173
174 In fact, we fully process all coincidences immediately. So,
175 outside of the coincidence processing routine, the coinc queue is
176 always empty. Since al0_compact isn't called during coincidence
177 handling, we're ok there. As for deductions, we _could_ work thro
178 the queue repeatedly as we compact, resetting the stored coset
179 numbers to their adjusted values, but we don't (v. expensive). We
180 just throw any outstanding deductions away, noting this in disded.
181 We worry later (if we get a finite result) about whether or not we
182 have to do any extra work to check whether this cavalier attitude
183 was `justified'.
184
185 Note that this routine is called `on-the-fly' by some of the Level
186 2 options. It can also be called directly by the rec[over] option.
187 ******************************************************************/
188
al0_compact(void)189 Logic al0_compact(void)
190 {
191 int i, j, irow, col;
192 int knra, knha;
193
194 /* Table is already compact, do nothing. */
195 if (nalive == nextdf-1)
196 { return(FALSE); }
197
198 /* Clear any preferred definitions on their queue. */
199 toppd = botpd = 0;
200
201 /* Throw away (after logging) any outstanding deductions. */
202 if (topded >= 0)
203 {
204 disded = TRUE;
205 topded = -1;
206 }
207
208 /* Zero the counters for knr/knh adjustment. Note that we can't adjust
209 these as we go, since it's their _original_ values which are relevant. */
210
211 knra = knha = 0;
212
213 /* Set irow to the lowest redundant coset (which is _never_ #1). */
214
215 for (irow = 2; irow < nextdf; irow++)
216 {
217 if (COL1(irow) < 0)
218 { break; }
219 }
220
221 /* Compact the coset table. */
222
223 for (i = irow; i < nextdf; i++)
224 {
225 if (COL1(i) < 0)
226 {
227 if (i <= knr)
228 { knra++; }
229 if (i <= knh)
230 { knha++; }
231 }
232 else
233 { /* Convert row i to row irow. */
234 for (col = 1; col <= ncol; col++)
235 {
236 if ((j = CT(i, col)) != 0)
237 {
238 if (j == i)
239 { j = irow; }
240 else
241 { CT(j, invcol[col]) = irow; }
242 }
243 CT(irow, col) = j;
244 }
245 irow++;
246 }
247 }
248
249 knr -= knra; /* Adjust counters */
250 knh -= knha;
251
252 nextdf = irow; /* 1st unused row */
253
254 return(TRUE);
255 }
256
257 /******************************************************************
258 Logic al0_stdct(void)
259
260 This companion programme to _compact() puts the table into standard
261 form. This form is based on the order of the generators in the
262 table, but is otherwise fixed for a given group/subgroup; it's
263 independant of the details of an enumeration. It allows canonic
264 rep'ves to be picked off by back-tracing (see al1_bldrep()). We
265 chose _not_ to combine _stdct() & _compact() into one routine,
266 since the core enumerator may compact (more than once) & we don't
267 want to impact it's speed with `unnecessary' work. After an
268 enumeration completes, a single call of _compact() & then of
269 _stdct() gives a hole-free, standardised table. We can standardise
270 holey-tables, but the result is only unique up to the set of coset
271 labels in use.
272
273 Similar remarks to those in _compact() regarding pdefns, dedns,
274 coincs, etc., etc. apply here. We return true if we actually
275 change anything, else false. We do the work in two stages, since
276 we want to avoid (possibly) throwing away dedns if we can avoid it.
277 Note that we have to do some work even if the table is already
278 standardised, since there is no quick way to check this. However,
279 the termination condition is next=nextdf, and this occurs generally
280 before we scan up to row=nextdf,
281 ******************************************************************/
282
al0_stdct(void)283 Logic al0_stdct(void)
284 {
285 int row, col, cos, next, icol, iicol, c1, c2, c3, c4;
286
287 /* Init next to 1st non-redundant coset > 1 */
288
289 next = 1;
290 do
291 { next++; }
292 while (next < nextdf && COL1(next) < 0);
293
294 if (next == nextdf)
295 { return(FALSE); } /* table is in standard form */
296
297 /* Find 1st non-std entry, if it exists */
298
299 for (row = 1; row < nextdf; row++)
300 {
301 if (COL1(row) >= 0)
302 {
303 for (col = 1; col <= ncol; col++)
304 {
305 if ((cos = CT(row,col)) > 0)
306 {
307 if (cos < next)
308 { ; } /* ok */
309 else if (cos == next)
310 { /* new next value; maybe finish */
311 do
312 { next++; }
313 while (next < nextdf && COL1(next) < 0);
314 if (next == nextdf)
315 { return(FALSE); }
316 }
317 else
318 { goto non_std; } /* table is non-std */
319 }
320 }
321 }
322 }
323
324 return(FALSE); /* Table is standard. Never get here ?! */
325
326 non_std:
327
328 /* Table is non-std, so we'll be changing it. Clear the preferred
329 definition queue, and throw away (after logging) any outstanding
330 deductions. */
331
332 toppd = botpd = 0;
333
334 if (topded >= 0)
335 {
336 disded = TRUE;
337 topded = -1;
338 }
339
340 /* Now work through the table, standardising it. For simplicity, we
341 `continue' the loops used above, restarting the inner (column) loop. */
342
343 for ( ; row < nextdf; row++)
344 {
345 if (COL1(row) >= 0)
346 {
347 for (col = 1; col <= ncol; col++)
348 {
349 if ((cos = CT(row,col)) > 0)
350 {
351 if (cos < next)
352 { ; }
353 else if (cos == next)
354 {
355 do
356 { next++; }
357 while (next < nextdf && COL1(next) < 0);
358 if (next == nextdf)
359 { return(TRUE); }
360 }
361 else
362 {
363 /* At this point, cos > next and we have to swap these rows.
364 Note that all entries in rows <row are <next, and will not be
365 effected. We process x/X pairs in one hit (to prevent any
366 nasties), so we skip over any 2nd (in order) occurrence of a
367 generator. Warning: trying to understand this code can cause
368 wetware malfunction! */
369
370 for (icol = 1; icol <= ncol; icol++)
371 {
372 iicol = invcol[icol];
373
374 if (icol < iicol)
375 {
376 c1 = CT(next,icol);
377 if (c1 == next)
378 { c1 = cos; }
379 else if (c1 == cos)
380 { c1 = next; }
381
382 c2 = CT(cos,icol);
383 if (c2 == next)
384 { c2 = cos; }
385 else if (c2 == cos)
386 { c2 = next; }
387
388 c3 = CT(next,iicol);
389 if (c3 == next)
390 { c3 = cos; }
391 else if (c3 == cos)
392 { c3 = next; }
393
394 c4 = CT(cos,iicol);
395 if (c4 == next)
396 { c4 = cos; }
397 else if (c4 == cos)
398 { c4 = next; }
399
400 CT(next,icol) = c2;
401 if (c2 != 0)
402 { CT(c2,iicol) = next; }
403
404 CT(cos,icol) = c1;
405 if (c1 != 0)
406 { CT(c1,iicol) = cos; }
407
408 CT(next,iicol) = c4;
409 if (c4 != 0)
410 { CT(c4,icol) = next; }
411
412 CT(cos,iicol) = c3;
413 if (c3 != 0)
414 { CT(c3,icol) = cos; }
415 }
416 else if (icol == iicol)
417 {
418 c1 = CT(next,icol);
419 if (c1 == next)
420 { c1 = cos; }
421 else if (c1 == cos)
422 { c1 = next; }
423
424 c2 = CT(cos,icol);
425 if (c2 == next)
426 { c2 = cos; }
427 else if (c2 == cos)
428 { c2 = next; }
429
430 CT(next,icol) = c2;
431 if (c2 != 0)
432 { CT(c2,icol) = next; }
433
434 CT(cos,icol) = c1;
435 if (c1 != 0)
436 { CT(c1,icol) = cos; }
437 }
438 }
439
440 do
441 { next++; }
442 while (next < nextdf && COL1(next) < 0);
443 if (next == nextdf)
444 { return(TRUE); }
445 }
446 }
447 }
448 }
449 }
450
451 return(TRUE);
452 }
453
454 /******************************************************************
455 double al0_nholes(void)
456
457 On flute, this processes `active' rows at ~ 5.10^6 entries/sec.
458 Note the use of knh to cut down the amount of work as much as
459 possible. Can be called by the TBA option of Level 2? Worst-case
460 complexity, in terms of the number of table accesses, is r(c+1);
461 where r/c are the number of rows/cols in the table.
462
463 Warning: possible int overflow of k for large tables.
464 ******************************************************************/
465
al0_nholes(void)466 double al0_nholes(void)
467 {
468 int i,j,k;
469
470 k = 0;
471 for (i = knh; i < nextdf; i++)
472 {
473 if (COL1(i) >= 0)
474 {
475 for (j = 1; j <= ncol; j++)
476 {
477 if (CT(i,j) == 0)
478 { k++; }
479 }
480 }
481 }
482
483 return( (100.0*(double)k) / ((double)ncol*(double)nalive) );
484 }
485
486 /******************************************************************
487 void al0_upknh(void)
488
489 Counts knh up to the next incomplete row, skipping redundants. We
490 either bail out at an empty table slot, or reach nextdf. During an
491 enumeration knh is maintained by C-style, due to its overloaded
492 meaning (ie, knh & knc). If we can't guarantee that the table is
493 hole-free in an R-style finite result, we have to run this check to
494 make sure. Worst-case complexity is r(c+1).
495
496 Note: this should not be called carelessly during an enumeration,
497 since it is important that knh-based C-style hole filling &
498 deduction stacking / processing are done together, due to the
499 overloading of knh's meaning & the fact that it triggers a finite
500 result if it hits nextdf. This should really only be called when
501 we _know_ we have a finite result (to check whether the table is
502 hole-free), or when we _know_ that all definitions have been
503 applied (perhaps in a C-style lookahead).
504 ******************************************************************/
505
al0_upknh(void)506 void al0_upknh(void)
507 {
508 int col;
509
510 for ( ; knh < nextdf; knh++)
511 {
512 if (COL1(knh) >= 0)
513 {
514 for (col = 1; col <= ncol; col++)
515 {
516 if (CT(knh,col) == 0)
517 { return; }
518 }
519 }
520 }
521 }
522
523 /******************************************************************
524 void al0_dedn(int cos, int gen)
525
526 Handling the deduction stack is a pain. The best option, in many
527 cases, seems to be to throw deductions away if we get too many at
528 any one time (where `too many' can be quite `small', eg, <1000),
529 and run an "RA:" or a "CL:" check. However, dedmode #4 (which is
530 the default) allows a special stack-handling function to be called
531 if we try to stack a deduction & can't.
532
533 Currently, in this mode our aim is _never_ to lose any deductions,
534 so we expand the stack space to accomodate the new element. We
535 take the opportunity to eliminate redundancies from the stack. The
536 code is essentially that used in dedmod #2 in _coinc() (which
537 emulates ACE2).
538
539 Note the messaging code, since we're interested in what the stack
540 actually `looks' like when it overflows! Some ad hoc tests show
541 that redundancies are common (in collapses). Duplicates (incl.
542 `inverted' duplicates) are not, and it's expensive to process
543 these, so we don't bother trying to track them.
544
545 Warning: this is the _only_ place in the core enumerator where we
546 make a system call (apart from o/p & date calls; if these fail
547 we've got real problems), and it's one which could fail. There is
548 _no_ mechanism in ACE Level 0 for handling these sorts of errors,
549 so we do the best we can to recover. Note also that there is no
550 cap on the amount of space which we'll (try to) allocate; so this
551 could all come crashing down in a heap!
552 ******************************************************************/
553
al0_dedn(int cos,int gen)554 void al0_dedn(int cos, int gen)
555 {
556 int i,j;
557 int dead = 0;
558
559 dedsiz *= 2; /* Best way to go? */
560 if ( (dedrow = (int *)realloc(dedrow, dedsiz*sizeof(int))) == NULL ||
561 (dedcol = (int *)realloc(dedcol, dedsiz*sizeof(int))) == NULL )
562 {
563 /* Our attempt to allocate more space failed, and we lost the existing
564 stack. Print out a nasty message (if messaging is on), and tidy up.
565 Note that the enumerator works correctly with dedsiz=0, but discards
566 _all_ deductions (& does so forever, since 2*0 = 0!). */
567
568 if (dedrow != NULL)
569 { free(dedrow); }
570 if (dedcol != NULL)
571 { free(dedcol); }
572 dedsiz = 0;
573 topded = -1;
574 disded = TRUE;
575
576 if (msgctrl)
577 { fprintf(fop, "DS: Unable to grow, all deductions discarded\n"); }
578
579 return;
580 }
581
582 /* Is is actually _worth_ doing this? In a big collapse, the proportion
583 of coinc dedns can be high; but these are skipped over when encountered
584 in _cdefn(), so why go to the expense of a (linear) pass & data move. It
585 might keep the stack size down and prevent one doubling, so we have a
586 time vs mempry trade-off (maybe). We could also be cleverer, and move
587 non-redundants from the top to redundant slots at the bottom, cutting the
588 number of data moves. */
589
590 j = -1;
591 i = 0;
592 while (i <= topded && COL1(dedrow[i]) >= 0)
593 { j++; i++; }
594 for ( ; i <= topded; i++)
595 {
596 if (COL1(dedrow[i]) >= 0)
597 {
598 dedrow[++j] = dedrow[i];
599 dedcol[j] = dedcol[i];
600 }
601 else
602 { dead++; } /* Track no. redundancies discarded. */
603 }
604 topded = j;
605
606 /* Now add the original cause of the problem. There's no need to check
607 for an overflow, since we're guaranteed to have enough space at this
608 point. Note however that we do need to take care to update sdmax
609 correctly if the stats package is on. */
610
611 dedrow[++topded] = cos;
612 dedcol[topded] = gen;
613 #ifdef AL0_STAT
614 if (topded >= sdmax)
615 { sdmax = topded+1; }
616 #endif
617
618 if (msgctrl)
619 {
620 msgnext = msgincr;
621 ETINT;
622 fprintf(fop, "DS: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
623 MSGMID;
624 fprintf(fop, " s=%d d=%d c=%d\n", dedsiz, topded+1, dead);
625 BTINT;
626 }
627 }
628
629 /******************************************************************
630 void al0_dump(Logic allofit)
631
632 Dump out the internals of Level 0 of ACE, working through al0.h
633 more or less in order. We could do more here in terms of pretty-
634 printing the data; or we could introduce further arguments
635 controlling the level of detail; or we could incorporate checks for
636 consistency; or ensure that this is only called when there's valid
637 data; or ... These are left as exercises for the reader; the
638 output is intended for debugging, and obscurity & information
639 overload are part of the game!
640 ******************************************************************/
641
al0_dump(Logic allofit)642 void al0_dump(Logic allofit)
643 {
644 int i,j;
645
646 fprintf(fop, " #---- %s: Level 0 Dump ----\n", ACE_VER);
647
648 /* FILE *fop, *fip; */
649 if (allofit)
650 {
651 if (fop == NULL)
652 { fop = stdout; fprintf(fop, "fop=NULL"); }
653 else if (fop == stdout)
654 { fprintf(fop, "fop=stdout"); }
655 else if (fop == stderr)
656 { fprintf(fop, "fop=stderr"); }
657 else
658 { fprintf(fop, "fop=(something)"); }
659 if (fip == NULL)
660 { fprintf(fop, " fip=NULL\n"); }
661 else if (fip == stdin)
662 { fprintf(fop, " fip=stdin\n"); }
663 else
664 { fprintf(fop, " fop=(something)\n"); }
665 }
666
667 /* double begintime, endtime, deltatime, totaltime; */
668 if (allofit)
669 {
670 fprintf(fop,
671 "begintime=%4.2f endtime=%4.2f deltatime=%4.2f totaltime=%4.2f\n",
672 begintime, endtime, deltatime, totaltime);
673 }
674
675 /* msgctrl, msghol, msgincr, msgnext; */
676 fprintf(fop, "msgctrl=%d msghol=%d msgincr=%d msgnext=%d\n",
677 msgctrl, msghol, msgincr, msgnext);
678
679 /* Logic mendel, rfill, pcomp; */
680 fprintf(fop, "mendel=%d rfill=%d pcomp=%d\n", mendel, rfill, pcomp);
681
682 /* int maxrow, rfactor, cfactor, comppc, nrinspg, lahead; */
683 fprintf(fop, "maxrow=%d rfactor=%d cfactor=%d\n",
684 maxrow, rfactor, cfactor);
685 fprintf(fop, "comppc=%d nrinsgp=%d lahead=%d\n",
686 comppc, nrinsgp, lahead);
687
688 /* int tlimit, hlimit, llimit, lcount */
689 fprintf(fop, "tlimit=%d hlimit=%d llimit=%d lcount=%d\n",
690 tlimit, hlimit, llimit, lcount);
691
692 /* int nalive, maxcos, totcos; */
693 fprintf(fop, "nalive=%d maxcos=%d totcos=%d\n", nalive, maxcos, totcos);
694
695 /* int chead, ctail; + coincidence queue */
696 fprintf(fop, "chead=%d ctail=%d", chead, ctail);
697 if (chead == 0)
698 { fprintf(fop, " (empty)\n"); }
699 else if (chead == ctail)
700 { fprintf(fop, " (%d->%d (+%d))\n",
701 chead, -COL1(chead), COL2(chead)); }
702 else
703 { fprintf(fop, " (%d->%d (+%d) ... %d->%d (+%d))\n", chead,
704 -COL1(chead), COL2(chead), ctail, -COL1(ctail), COL2(ctail)); }
705
706 /* int pdefn, ffactor, pdsiz; */
707 fprintf(fop, "pdefn=%d ffactor=%3.1f pdsiz=%d\n", pdefn, ffactor, pdsiz);
708
709 /* int toppd, botpd; + int pdqcol[], pdqrow[]; */
710 fprintf(fop, "toppd=%d botpd=%d", toppd, botpd);
711 if (toppd == botpd)
712 { fprintf(fop, " (empty)\n"); }
713 else
714 { fprintf(fop, " (pdqrow/col=%d.%d ...)\n",
715 pdqrow[toppd], pdqcol[toppd]); }
716
717 /* int dedsiz, topded, disded, dedmode; + int *dedrow, *dedcol; */
718 fprintf(fop, "dedmode=%d dedsiz=%d disded=%d topded=%d",
719 dedmode, dedsiz, disded, topded);
720 if (topded < 0)
721 { fprintf(fop, " (empty)\n"); }
722 else
723 { fprintf(fop, " (... dedrow/col=%d.%d)\n",
724 dedrow[topded], dedcol[topded]); }
725
726 /* int *edp, *edpbeg, *edpend; */
727 if (allofit)
728 {
729 if (edp == NULL)
730 { fprintf(fop, "edp=NULL\n"); }
731 else
732 {
733 fprintf(fop, "edpbeg edpend edp[]\n");
734 for (i = 1; i <= ncol; i++)
735 {
736 if (edpbeg[i] >= 0)
737 {
738 fprintf(fop, "%5d %5d ", edpbeg[i], edpend[i]);
739 for (j = edpbeg[i]; j <= edpend[i]; j++, j++)
740 { fprintf(fop, " %d(%d)", edp[j], edp[j+1]); }
741 }
742 else
743 { fprintf(fop, "%5d %5d -", edpbeg[i], edpend[i]);}
744 fprintf(fop, "\n");
745 }
746 }
747 }
748
749 /* int ncol, **colptr (+ col1ptr/col2ptr ?), *invcol; */
750 if (allofit)
751 {
752 fprintf(fop, "ncol=%d\n", ncol);
753 if (colptr == NULL)
754 { fprintf(fop, "colptr=NULL\n"); }
755 else
756 {
757 fprintf(fop, " invcol[] ");
758 for (i = 1; i <= ncol; i++)
759 { fprintf(fop, " %4d", invcol[i]); }
760 fprintf(fop, "\n");
761
762 fprintf(fop, " colptr[][1] ");
763 for (i = 1; i <= ncol; i++)
764 { fprintf(fop, " %4d", colptr[i][1]); }
765 fprintf(fop, "\n");
766
767 fprintf(fop, " CT(2,) ");
768 for (i = 1; i <= ncol; i++)
769 { fprintf(fop, " %4d", CT(2,i)); }
770 fprintf(fop, "\n");
771 }
772 }
773 else
774 { fprintf(fop, "ncol=%d", ncol); }
775
776 /* int ndrel, *relind, *relexp, *rellen, *relators; */
777 if (allofit)
778 {
779 fprintf(fop, "ndrel=%d\n", ndrel);
780 if (relators == NULL)
781 { fprintf(fop, "relators=NULL\n"); }
782 else
783 {
784 fprintf(fop, " rellen relexp relind relators[]\n");
785 for (i = 1; i <= ndrel; i++)
786 {
787 fprintf(fop, " %5d %5d %5d ", rellen[i], relexp[i], relind[i]);
788 for (j = relind[i]; j < relind[i]+rellen[i]; j++)
789 { fprintf(fop, " %d", relators[j]); }
790 fprintf(fop, " ");
791 for ( ; j < relind[i]+2*rellen[i]; j++)
792 { fprintf(fop, " %d", relators[j]); }
793 fprintf(fop, "\n");
794 }
795 }
796 }
797 else
798 { fprintf(fop, " ndrel=%d", ndrel); }
799
800 /* int nsgpg, *subggen, *subgindex, *subglength, sgdone; */
801 if (allofit)
802 {
803 fprintf(fop, "nsgpg=%d sgdone=%d\n", nsgpg, sgdone);
804 if (subggen == NULL)
805 { fprintf(fop, "subggen=NULL\n"); }
806 else
807 {
808 fprintf(fop, " subglength subgindex subggen[]\n");
809 for (i = 1; i <= nsgpg; i++)
810 {
811 fprintf(fop, " %8d %7d ", subglength[i], subgindex[i]);
812 for (j = subgindex[i]; j < subgindex[i]+subglength[i]; j++)
813 { fprintf(fop, " %d", subggen[j]); }
814 fprintf(fop, "\n");
815 }
816 }
817 }
818 else
819 { fprintf(fop, " nsgpg=%d sgdone=%d\n", nsgpg, sgdone); }
820
821 /* int knr, knh, nextdf; */
822 fprintf(fop, "knr=%d knh=%d nextdf=%d\n",
823 knr, knh, nextdf);
824
825 fprintf(fop, " #---------------------------------\n");
826 }
827
828 /******************************************************************
829 void al0_rslt(int rslt)
830
831 Pretty-print the result of a run, and some gross statistics.
832 ******************************************************************/
833
al0_rslt(int rslt)834 void al0_rslt(int rslt)
835 {
836 if (rslt >= 1)
837 {
838 fprintf(fop, "INDEX = %d", rslt);
839 fprintf(fop, " (a=%d r=%d h=%d n=%d; l=%d c=%4.2f; m=%d t=%d)\n",
840 nalive, knr, knh, nextdf, lcount, totaltime, maxcos, totcos);
841 }
842 else
843 {
844 switch(rslt)
845 {
846 case -4097: fprintf(fop, "BAD FINITE RESULT"); break;
847 case -4096: fprintf(fop, "BAD MACHINE STATE"); break;
848 case -514: fprintf(fop, "INVALID MODE/STYLE"); break;
849 case -513: fprintf(fop, "INVALID STYLE"); break;
850 case -512: fprintf(fop, "INVALID MODE"); break;
851 case -260: fprintf(fop, "SG PHASE OVERFLOW"); break;
852 case -259: fprintf(fop, "ITERATION LIMIT"); break;
853 case -258: fprintf(fop, "TIME LIMT"); break;
854 case -257: fprintf(fop, "HOLE LIMIT"); break;
855 case -256: fprintf(fop, "INCOMPLETE TABLE"); break;
856 case 0: fprintf(fop, "OVERFLOW"); break;
857 default: fprintf(fop, "UNKNOWN ERROR (%d)", rslt); break;
858 }
859
860 if (rslt <= -512)
861 { fprintf(fop, "\n"); }
862 else
863 {
864 fprintf(fop, " (a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
865 if (msghol)
866 { fprintf(fop, " h=%4.2f%%", al0_nholes()); }
867 fprintf(fop, " l=%d c=%4.2f;", lcount, totaltime);
868 fprintf(fop, " m=%d t=%d)\n", maxcos, totcos);
869 }
870 }
871 }
872
873 #ifdef AL0_STAT
874
875 /******************************************************************
876 void al0_statinit(void)
877
878 Initialise the stats package for this call to al0_enum().
879 ******************************************************************/
880
al0_statinit(void)881 void al0_statinit(void)
882 {
883 cdcoinc = rdcoinc = apcoinc = rlcoinc = clcoinc = 0;
884 xcols12 = xcoinc = qcoinc = 0;
885 xsave12 = s12dup = s12new = 0;
886 xcrep = crepred = crepwrk = 0;
887 xcomp = compwrk = 0;
888 xsaved = sdmax = sdoflow = 0;
889 xapply = apdedn = apdefn = 0;
890 rldedn = cldedn = 0;
891 xrdefn = rddedn = rddefn = rdfill = 0;
892 xcdefn = cddproc = cdddedn = cddedn = cdgap = cdidefn = 0;
893 cdidedn = cdpdl = cdpof = cdpdead = cdpdefn = cddefn = 0;
894 }
895
896 /******************************************************************
897 void al0_statdump(void)
898
899 Dump the stats for latest call to al0_enum().
900 ******************************************************************/
901
al0_statdump(void)902 void al0_statdump(void)
903 {
904 fprintf(fop, " #- %s: Level 0 Statistics -\n", ACE_VER);
905
906 fprintf(fop, "cdcoinc=%d rdcoinc=%d apcoinc=%d rlcoinc=%d clcoinc=%d\n",
907 cdcoinc, rdcoinc, apcoinc, rlcoinc, clcoinc);
908 fprintf(fop, " xcoinc=%d xcols12=%d qcoinc=%d\n",
909 xcoinc, xcols12, qcoinc);
910 fprintf(fop, " xsave12=%d s12dup=%d s12new=%d\n",
911 xsave12, s12dup, s12new);
912 fprintf(fop, " xcrep=%d crepred=%d crepwrk=%d xcomp=%d compwrk=%d\n",
913 xcrep, crepred, crepwrk, xcomp, compwrk);
914 fprintf(fop, "xsaved=%d sdmax=%d sdoflow=%d\n", xsaved, sdmax, sdoflow);
915 fprintf(fop, "xapply=%d apdedn=%d apdefn=%d\n", xapply, apdedn, apdefn);
916 fprintf(fop, "rldedn=%d cldedn=%d\n", rldedn, cldedn);
917 fprintf(fop, "xrdefn=%d rddedn=%d rddefn=%d rdfill=%d\n",
918 xrdefn, rddedn, rddefn, rdfill);
919 fprintf(fop, "xcdefn=%d cddproc=%d cdddedn=%d cddedn=%d\n",
920 xcdefn, cddproc, cdddedn, cddedn);
921 fprintf(fop, " cdgap=%d cdidefn=%d cdidedn=%d cdpdl=%d cdpof=%d\n",
922 cdgap, cdidefn, cdidedn, cdpdl, cdpof);
923 fprintf(fop, " cdpdead=%d cdpdefn=%d cddefn=%d\n",
924 cdpdead, cdpdefn, cddefn);
925
926 fprintf(fop, " #---------------------------------\n");
927 }
928
929 #endif
930
931