1 /* File generate.c. */
2 
3 /* Copyright (C) 1992 by Jeffrey S. Leon.  This software may be used freely
4    for educational and research purposes.  Any other use requires permission
5    from the author. */
6 
7 /*  Main program for generate command, which may be used
8    to find a base and strong generating set for a permutation group using
9    the random Schreier and/or Schreier-Todd-Coxeter-Sims methods.  The format
10    of the command is:
11 
12       generate  <options>  <permGroup>  <generatedPermGroup>
13 
14    where the meaning of the parameters is as follows:
15 
16       <permGroup>:          the permutation group G for which a base and strong
17                             generating set is to be found.
18 
19       <generatedPermGroup>: the same permutation group G with a base and strong
20                             generating set, depending on options, possibly a
21                             strong presentation.
22 
23    The general options are as follows:
24 
25       -nr            Omit random-Schreier phase.
26 
27       -ns            Omit Schreier-Todd-Coxeter-Sims phase (automatically
28                      omitted if order is known in advance and random-Schreier
29                      phases generates full order, unless the -p option is given.
30 
31       -p             Find a presentation.
32 
33       -q             Don't write status information to standard output.
34 
35       -in:<group>    Group G is contained in <group>.  Only base of <group> is
36                      used; <group> need not be valid as long as its base ,
37                      base size, and degree fields are filled in correctly.
38 
39       -overwrite     Overwrite, rather than append to, the output file.
40 
41       -i             Image format for output group.
42 
43       -c             Cycle format for output group.
44 
45       -gn:<name>
46 
47    Options applicable specifically to the random-Schreier phase are:
48 
49       -s:<integer>    Seed for random number generator.
50 
51       -tr:<integer>   Random Schreier phase terminates after this many
52                       consecutive "successes" (quasi-random elements that
53                       are factorable).
54 
55       -ti:<integer>   This many consecutive non-involutory generators will
56                       be rejected in an attempt to choose involutory generators.
57 
58       -th:k           This many consecutive generators will be rejected in
59                       an attempt to choose a generator of order 3 (or less).
60 
61       -nro            Suppress normal attempt to reduce generator order by
62                       replacing generators with powers.
63 
64       -wi:w,x         Here w and x are integers with w <= x.  The word length
65                       increment will be random between w and x.
66 
67       -z              Redundant strong generators will be removed after the
68                       algorithm completes..
69 
70    Options applicable to the STCS phase are:
71 
72       -go:m           Automatically include the order of each generator as a
73                       relator when the generator order does not exceed m
74                       (default 15).
75 
76       -po:m           Automatically include the order of each product of
77                       generators as a relator when the product order does
78                       not exceed m (default 5).
79 
80       -x2:m           If the STCS phase terminates with more than
81                       m generators (excluding inverses), redundant generators
82                       are removed.
83 
84       -pr:a,b,c,d,e   Determines priority for relator selection.  The priority
85                       of a relator r is  a - b * (len+symLen)/2.  Relators are
86                       selected if their priority exceeds
87                       c + d * chosen - e * omitted, where chosen represents the
88                       number of relators chosen at this level and omitted
89                       represents the number not chosen.
90 
91       -sh:i1,k1,i2..  Specifies which cyclic shifts of relators will be
92                       used in the Felsch enumeration.  Specifies that an
93                       i1 position shift will be used if the relator
94                       priority exceeds the selection priority by at least
95                       k1, etc.  By default, all shifts are always used.
96       -x:k            Specifies use of up to k extra cosets during enumeration
97                       (default 0).  When k > 0, a different procedure is
98                       used to check point stabilizers.
99 
100       -y:m            The number of extra cosets used will be
101                       m/100 * degree (rounded up), but in no case more than
102                       k, as above  (default 10). */
103 
104 
105 #include <stddef.h>
106 #include <errno.h>
107 #include <stdlib.h>
108 #include <stdio.h>
109 #include <string.h>
110 #include <time.h>
111 
112 #define MAIN
113 
114 #include "group.h"
115 #include "groupio.h"
116 #include "enum.h"
117 #include "storage.h"
118 
119 #ifdef ALT_TIME_HEADER
120 #include "cputime.h"
121 #endif
122 
123 #ifdef TICK
124 #undef CLK_TCK
125 #define CLK_TCK TICK
126 #endif
127 
128 #include "errmesg.h"
129 #include "new.h"
130 #include "readgrp.h"
131 #include "randschr.h"
132 #include "stcs.h"
133 #include "util.h"
134 
135 static void nameGenerators(
136    PermGroup *const H,
137    char genNamePrefix[]);
138 
139 static void informGenerateTime(
140    clock_t startTime,
141    clock_t randSchrTime,
142    clock_t optGroupTime,
143    clock_t stcsTime);
144 
145 static void verifyOptions(void);
146 
147 GroupOptions options;
148 STCSOptions sOptions;
149 
150 Unsigned relatorSelection[5] = {1000,0,800,0,0};
151 Unsigned shiftSelection[11] = {UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
152                                UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
153                                UNKNOWN};
154 Unsigned shiftPriority[11];
155 
156 
main(int argc,char * argv[])157 int main( int argc, char *argv[])
158 {
159    char groupFileName[MAX_FILE_NAME_LENGTH] = "",
160         genGroupFileName[MAX_FILE_NAME_LENGTH] = "",
161         containingGroupFileName[MAX_FILE_NAME_LENGTH] = "";
162    char groupLibraryName[MAX_NAME_LENGTH+1] = "",
163         genGroupLibraryName[MAX_NAME_LENGTH+1] = "",
164         genGroupObjectName[MAX_NAME_LENGTH+1] = "",
165         containingGroupLibraryName[MAX_NAME_LENGTH+1] = "",
166         prefix[MAX_FILE_NAME_LENGTH],
167         suffix[MAX_NAME_LENGTH];
168    Unsigned i, j, optionCountPlus1, level;
169    BOOLEAN omitRandomSchreierOption, omitStcsOption, presentationOption,
170            quietOption, cycleFormatFlag, imageFormatFlag, removeRedunStrGens,
171            noBackupFlag;
172    Unsigned trimStrGenSet1, trimStrGenSet2;
173    PermGroup *G, *containingGroup;
174    char comment[60] = "";
175    UnsignedS *pointList = allocIntArrayBaseSize();
176    char tempStr[12];
177    char *strPtr, *commaPtr;
178    Unsigned *knownBase = allocIntArrayBaseSize();
179    RandomSchreierOptions rOptions = {47,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
180                                      UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN};
181    clock_t        startTime, randSchrTime, optGroupTime, stcsTime;
182 
183 
184    /* Provide usage info if no arguments are specified. */
185    if ( argc == 1 ) {
186       printf( "\nUsage:  generate [options] originalPermGroup permGroupWithBaseSGS\n");
187       freeIntArrayBaseSize( pointList);
188       freeIntArrayBaseSize( knownBase);
189       return 0;
190    }
191 
192    /* Check for limits option.  If present in position 1 give limits and
193       return. */
194    if ( strcmp( argv[1], "-l") == 0 || strcmp( argv[1], "-L") == 0 ) {
195       showLimits();
196       freeIntArrayBaseSize( pointList);
197       freeIntArrayBaseSize( knownBase);
198       return 0;
199    }
200 
201    /* Check for verify option.  If present, perform verify (Note verifyOptions
202       terminates program). */
203    if ( strcmp( argv[1], "-v") == 0 || strcmp( argv[1], "-V") == 0 )
204       verifyOptions();
205 
206    /* Check for 1 or 2 parameters following options. */
207       for ( optionCountPlus1 = 1 ; optionCountPlus1 <= argc-1 &&
208                  argv[optionCountPlus1][0] == '-' ; ++optionCountPlus1 )
209          ;
210 
211       if ( argc - optionCountPlus1 < 1 || argc - optionCountPlus1 > 2 ) {
212          printf( "\n\nError: 1 or 2 non-option parameters are required.\n");
213          exit(ERROR_RETURN_CODE);
214       }
215 
216    /* Process options. */
217    prefix[0] = '\0';
218    suffix[0] = '\0';
219    options.maxBaseSize = DEFAULT_MAX_BASE_SIZE;
220    sOptions.maxDeducQueueSize = UNKNOWN;
221    sOptions.genOrderLimit = 13;
222    sOptions.prodOrderLimit = 3;
223    sOptions.maxExtraCosets = 0;
224    sOptions.percentExtraCosets = 10;
225    omitRandomSchreierOption = FALSE;
226    omitStcsOption = TRUE;
227    presentationOption = FALSE;
228    rOptions.reduceGenOrder = TRUE;
229    rOptions.rejectNonInvols = 0;
230    removeRedunStrGens = FALSE;
231    quietOption = FALSE;
232    options.genNamePrefix[0] = '\0';
233    trimStrGenSet1 = 20;
234    trimStrGenSet2 = 20;
235    cycleFormatFlag = FALSE;
236    imageFormatFlag = FALSE;
237    noBackupFlag = FALSE;
238    strcpy( options.outputFileMode, "w");
239    strcpy( options.genNamePrefix, "");
240 
241    for ( i = 1 ; i < optionCountPlus1 ; ++i )
242 
243       /* General options. */
244       if ( strcmp( argv[i], "-a") == 0 )
245          strcpy( options.outputFileMode, "a");
246       else if ( strcmp( argv[i], "-c") == 0 )
247          cycleFormatFlag = TRUE;
248       else if ( strcmp( argv[i], "-i") == 0 )
249          imageFormatFlag = TRUE;
250       else if ( strncmp( argv[i], "-mb:", 4) == 0 ) {
251          errno = 0;
252          options.maxBaseSize = (Unsigned) strtol(argv[i]+4,NULL,0);
253          if ( errno )
254             ERROR( "main (cent)", "Invalid syntax for -mb option")
255       }
256       else if ( strncmp( argv[i], "-mw:", 4) == 0 ) {
257          errno = 0;
258          options.maxWordLength = (Unsigned) strtol(argv[i]+4,NULL,0);
259          if ( errno )
260             ERROR( "main (cent)", "Invalid syntax for -mw option")
261       }
262       else if ( strncmp(argv[i],"-n:",3) == 0 )
263          strcpy( genGroupObjectName, argv[i]+3);
264       else if ( strcmp( argv[i], "-nb") == 0 )
265          noBackupFlag = TRUE;
266       else if ( strcmp( argv[i], "-overwrite") == 0 )
267          strcpy( options.outputFileMode, "w");
268       else if ( strncmp( argv[i], "-p:", 3) == 0 ) {
269          strcpy( prefix, argv[i]+3);
270       }
271       else if ( strcmp( argv[i], "-q") == 0 )
272          quietOption = TRUE;
273       else if ( strncmp( argv[i], "-t:", 3) == 0 ) {
274          strcpy( suffix, argv[i]+3);
275       }
276       else if ( strcmp( argv[i], "-z") == 0 ) {
277          removeRedunStrGens = TRUE;
278       }
279 
280       /* Method selection options. */
281       else if ( strcmp( argv[i], "-nr") == 0 )
282          omitRandomSchreierOption = TRUE;
283       else if ( strcmp( argv[i], "-stcs") == 0 )
284          omitStcsOption = FALSE;
285 
286       /* Random Schreier options. */
287       else if ( strcmp( argv[i], "-nro") == 0 )
288          rOptions.reduceGenOrder = FALSE;
289       else if ( strncmp(argv[i],"-s:",3) == 0 ) {
290          errno = 0;
291          rOptions.initialSeed = (unsigned long) strtol( argv[i]+3, NULL, 0);
292          if ( errno )
293             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
294       }
295       else if ( strncmp(argv[i],"-ti:",4) == 0 ) {
296          errno = 0;
297          rOptions.rejectNonInvols = (unsigned long) strtol( argv[i]+4, NULL, 0);
298          if ( errno )
299             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
300       }
301       else if ( strncmp(argv[i],"-tr:",4) == 0 ) {
302          errno = 0;
303          rOptions.stopAfter = (unsigned long) strtol( argv[i]+4, NULL, 0);
304          if ( errno )
305             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
306       }
307       else if ( strncmp( argv[i], "-wi:", 4) == 0 ) {
308          errno = 0;
309          rOptions.minWordLengthIncrement = (unsigned long) strtol( argv[i]+4, &commaPtr, 0);
310          if ( errno || *commaPtr != ',' )
311             ERROR1s( "main (generate command)", "Invalid syntax in option ",
312                      argv[i], ".")
313          rOptions.maxWordLengthIncrement = (unsigned long) strtol( commaPtr+1, NULL, 0);
314          if ( errno )
315             ERROR1s( "main (generate command)", "Invalid syntax in option ",
316                      argv[i], ".")
317       }
318 
319       /* STCS options. */
320       else if ( strncmp( argv[i], "-in:", 4) == 0 ) {
321          parseLibraryName( argv[i]+4, "", "", containingGroupFileName,
322                                               containingGroupLibraryName);
323       }
324       else if ( strncmp(argv[i],"-pr:",4) == 0 ) {
325          errno = 0;
326          commaPtr = argv[i]+3;
327          for ( j = 0 ; j <= 4 ; ++j ) {
328             strPtr = commaPtr + 1;
329             relatorSelection[j] = (Unsigned) (unsigned long) strtol( strPtr, &commaPtr, 0);
330             if ( errno || ( j < 4 && *commaPtr != ',') )
331                ERROR1s( "main (generate command)", "Invalid option ", argv[i],
332                         ".")
333          }
334       }
335       else if ( strncmp(argv[i],"-sh:",4) == 0 ) {
336          errno = 0;
337          commaPtr = argv[i]+3;
338          for ( j = 0 ; j < 10 && *commaPtr != '\0' ; ++j ) {
339             strPtr = commaPtr + 1;
340             shiftSelection[j] = (Unsigned) (unsigned long) strtol( strPtr, &commaPtr, 0);
341             if ( errno || *commaPtr != ',' )
342                ERROR1s( "main (generate command)", "Invalid option ", argv[i],
343                         ".")
344             strPtr = commaPtr + 1;
345             shiftPriority[j] = (Unsigned) (unsigned long) strtol( strPtr, &commaPtr, 0);
346             if ( errno || (*commaPtr != ',' && *commaPtr != '\0') )
347                ERROR1s( "main (generate command)", "Invalid option ", argv[i],
348                         ".")
349          }
350       }
351       else if ( strncmp(argv[i],"-th:",4) == 0 ) {
352          errno = 0;
353          rOptions.rejectHighOrder = (unsigned long) strtol( argv[i]+4, NULL, 0);
354          if ( errno )
355             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
356       }
357       else if ( strncmp(argv[i],"-go:",4) == 0 ) {
358          errno = 0;
359          sOptions.genOrderLimit = (unsigned long) strtol( argv[i]+4, NULL, 0);
360          if ( errno )
361             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
362       }
363       else if ( strncmp(argv[i],"-po:",4) == 0 ) {
364          errno = 0;
365          sOptions.prodOrderLimit = (unsigned long) strtol( argv[i]+4, NULL, 0);
366          if ( errno )
367             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
368       }
369       else if ( strncmp(argv[i],"-x:",3) == 0 ) {
370          errno = 0;
371          sOptions.maxExtraCosets = (unsigned long) strtol( argv[i]+3, NULL, 0);
372          if ( errno )
373             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
374       }
375       else if ( strncmp(argv[i],"-y:",3) == 0 ) {
376          errno = 0;
377          sOptions.percentExtraCosets = (unsigned long) strtol( argv[i]+3, NULL, 0);
378          if ( errno )
379             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
380       }
381       else
382             ERROR1s( "main (generate command)", "Invalid option ", argv[i], ".")
383 
384    /* Compute maximum degree and word length. */
385    options.maxWordLength = 200 + 5 * options.maxBaseSize;
386    options.maxDegree = MAX_INT - 2 - options.maxBaseSize;
387 
388 
389    /* Compute names for input and output groups. */
390    parseLibraryName( argv[optionCountPlus1], prefix, suffix, groupFileName,
391                      groupLibraryName);
392    if ( argc - optionCountPlus1 == 2 )
393       parseLibraryName( argv[optionCountPlus1+1], "", "", genGroupFileName,
394                         genGroupLibraryName);
395    else {
396       strcpy( genGroupFileName, groupFileName);
397       strcpy( genGroupLibraryName, groupLibraryName);
398    }
399 
400    /* Set initialize option for STCS. */
401    sOptions.initialize = omitRandomSchreierOption;
402 
403    /* Set default generator name prefix, if not specified. */
404    if ( options.genNamePrefix[0] == ' ' )
405       strncpy( options.genNamePrefix, genGroupLibraryName, 4);
406 
407    /* Read in input group, and base for containing group, if requested. */
408    G = readPermGroup( groupFileName, groupLibraryName, 0, "");
409    if ( containingGroupFileName[0] ) {
410       containingGroup = readPermGroup( containingGroupFileName,
411                                  containingGroupLibraryName, G->degree, "");
412       for ( i = 1 ; i <= containingGroup->baseSize ; ++i )
413          knownBase[i] = containingGroup->base[i];
414       knownBase[containingGroup->baseSize+1] = 0;
415       deletePermGroup( containingGroup);
416    }
417 
418    startTime = CPU_TIME();
419 
420    /* Apply random Schreier algorithm. */
421    if ( !omitRandomSchreierOption ) {
422       /* SETUP OPTIONS STRING */
423       randomSchreier( G, rOptions);
424       if ( removeRedunStrGens )
425          removeRedunSGens( G, 1);
426    }
427    randSchrTime = CPU_TIME();
428 
429    optGroupTime = CPU_TIME();
430 
431    /* Apply Schreier-Todd-Coxeter-Sims algorithm, if appropriate. */
432    if ( !omitStcsOption /* FIX THIS */ )
433       schreierToddCoxeterSims( G, knownBase);
434    stcsTime = CPU_TIME();
435 
436    if ( !quietOption ) {
437       informGroup(G);
438       printf( "\n  Base:               ");
439       for ( level = 1 ; level <= G->baseSize ; ++level )
440          printf( " %5u", G->base[level]);
441       printf(   "\n  Basic orbit lengths:");
442       for ( level = 1 ; level <= G->baseSize ; ++level )
443          printf( " %5u", G->basicOrbLen[level]);
444       printf( "\n");
445       informGenerateTime( startTime, randSchrTime, optGroupTime, stcsTime);
446    }
447 
448    /* Write out the generated group. */
449    sprintf( comment, "The group %s, base and strong generating set constucted.",
450             G->name);
451    if ( cycleFormatFlag )
452       G->printFormat = cycleFormat;
453    if ( imageFormatFlag )
454       G->printFormat = imageFormat;
455    if ( genGroupObjectName[0] )
456       strcpy( G->name, genGroupObjectName);
457    if ( argc - optionCountPlus1 == 1 && !noBackupFlag )
458       if ( rename(groupFileName,"oldgroup") == -1 )
459          ERROR1s( "main (generate command)", "Original group ", groupFileName,
460                   " could not be renamed as oldgroup.")
461 
462    writePermGroup( genGroupFileName, genGroupLibraryName, G, comment);
463 
464    /* Free pseudo-stack storage. */
465    freeIntArrayBaseSize( pointList);
466    freeIntArrayBaseSize( knownBase);
467 
468    return 0;
469 }
470 
471 
472 /*-------------------------- nameGenerators ------------------------------*/
473 
nameGenerators(PermGroup * const H,char genNamePrefix[])474 static void nameGenerators(
475    PermGroup *const H,
476    char genNamePrefix[])
477 {
478    Unsigned i;
479    Permutation *gen;
480 
481    if ( genNamePrefix[0] == '\0' ) {
482       strncpy( genNamePrefix, H->name, 4);
483       genNamePrefix[4] = '\0';
484    }
485    for ( gen = H->generator , i = 1 ; gen ; gen = gen->next , ++i ) {
486       strcpy( gen->name, genNamePrefix);
487       sprintf( gen->name + strlen(gen->name), "%02d", i);
488    }
489 }
490 
491 
492 /*-------------------------- verifyOptions -------------------------------*/
493 
verifyOptions(void)494 static void verifyOptions(void)
495 {
496    CompileOptions mainOpts = { DEFAULT_MAX_BASE_SIZE, MAX_NAME_LENGTH,
497                                MAX_PRIME_FACTORS,
498                                MAX_REFINEMENT_PARMS, MAX_FAMILY_PARMS,
499                                MAX_EXTRA,  XLARGE, SGND, NFLT};
500    extern void xaddsge( CompileOptions *cOpts);
501    extern void xbitman( CompileOptions *cOpts);
502    extern void xchbase( CompileOptions *cOpts);
503    extern void xcopy  ( CompileOptions *cOpts);
504    extern void xcstbor( CompileOptions *cOpts);
505    extern void xerrmes( CompileOptions *cOpts);
506    extern void xessent( CompileOptions *cOpts);
507    extern void xfactor( CompileOptions *cOpts);
508    extern void xinform( CompileOptions *cOpts);
509    extern void xnew   ( CompileOptions *cOpts);
510    extern void xoldcop( CompileOptions *cOpts);
511    extern void xpermgr( CompileOptions *cOpts);
512    extern void xpermut( CompileOptions *cOpts);
513    extern void xprimes( CompileOptions *cOpts);
514    extern void xrandgr( CompileOptions *cOpts);
515    extern void xrandsc( CompileOptions *cOpts);
516    extern void xreadgr( CompileOptions *cOpts);
517    extern void xrelato( CompileOptions *cOpts);
518    extern void xstcs  ( CompileOptions *cOpts);
519    extern void xstorag( CompileOptions *cOpts);
520    extern void xtoken ( CompileOptions *cOpts);
521    extern void xutil  ( CompileOptions *cOpts);
522 
523    xaddsge( &mainOpts);
524    xbitman( &mainOpts);
525    xchbase( &mainOpts);
526    xcopy  ( &mainOpts);
527    xcstbor( &mainOpts);
528    xerrmes( &mainOpts);
529    xessent( &mainOpts);
530    xfactor( &mainOpts);
531    xinform( &mainOpts);
532    xnew   ( &mainOpts);
533    xoldcop( &mainOpts);
534    xpermgr( &mainOpts);
535    xpermut( &mainOpts);
536    xprimes( &mainOpts);
537    xrandgr( &mainOpts);
538    xrandsc( &mainOpts);
539    xreadgr( &mainOpts);
540    xrelato( &mainOpts);
541    xstcs  ( &mainOpts);
542    xstorag( &mainOpts);
543    xtoken ( &mainOpts);
544    xutil  ( &mainOpts);
545 }
546 
547 
548 /*-------------------------- informGenerateTime ----------------------------*/
549 
informGenerateTime(clock_t startTime,clock_t randSchrTime,clock_t optGroupTime,clock_t stcsTime)550 static void informGenerateTime(
551    clock_t startTime,
552    clock_t randSchrTime,
553    clock_t optGroupTime,
554    clock_t stcsTime)
555 {
556    clock_t  totalTime;
557 #ifdef NOFLOAT
558    unsigned long secs, hSecs;
559 #endif
560 
561    stcsTime -= optGroupTime;
562    optGroupTime -= randSchrTime;
563    randSchrTime -= startTime;
564    totalTime = randSchrTime + optGroupTime + stcsTime;
565 
566 #ifndef NOFLOAT
567    printf(   "\nTime:   Random Schreier:    %6.2lf sec",
568                         (double) randSchrTime / CLK_TCK);
569    printf(   "\n        Gen optimization:   %6.2lf sec",
570                         (double) optGroupTime / CLK_TCK);
571    printf(   "\n        Schr-Todd-Cox-Sims: %6.2lf sec",
572                         (double) stcsTime / CLK_TCK);
573    printf(   "\n        TOTAL:              %6.2lf sec",
574                         (double) totalTime / CLK_TCK);
575 #endif
576 
577 #ifdef NOFLOAT
578    secs = randSchrTime / CLK_TCK;
579    hSecs = (randSchrTime - secs * CLK_TCK) * 100;
580    hSecs /= CLK_TCK;
581    printf(   "\nTime:   Random Schreier:    %4lu.%02lu sec", secs, hSecs);
582    secs = optGroupTime / CLK_TCK;
583    hSecs = (optGroupTime - secs * CLK_TCK) * 100;
584    hSecs /= CLK_TCK;
585    printf(   "\n        Gen optimization:   %4lu.%02lu sec", secs, hSecs);
586    secs = stcsTime / CLK_TCK;
587    hSecs = (stcsTime - secs * CLK_TCK) * 100;
588    hSecs /= CLK_TCK;
589    printf(   "\n        Schr-Todd-Cox-Sims: %4lu.%02lu sec", secs, hSecs);
590    secs = totalTime / CLK_TCK;
591    hSecs = (totalTime - secs * CLK_TCK) * 100;
592    hSecs /= CLK_TCK;
593    printf(   "\n        TOTAL:              %4lu.%02lu sec", secs, hSecs);
594 #endif
595 
596    printf(   "\n");
597 }
598