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