COSC-4P82-Final-Project/lib/lilgp/kernel/main.c

902 lines
30 KiB
C

/* lil-gp Genetic Programming System, version 1.0, 11 July 1995
* Copyright (C) 1995 Michigan State University
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Douglas Zongker (zongker@isl.cps.msu.edu)
* Dr. Bill Punch (punch@isl.cps.msu.edu)
*
* Computer Science Department
* A-714 Wells Hall
* Michigan State University
* East Lansing, Michigan 48824
* USA
*
*/
#include <lilgp.h>
#include <pthread.h>
#ifdef MEMORY_LOG
FILE *mlog;
#endif
/* do we dup OUT_SYS to stdout? */
int quietmode = 0;
/* tree generation spaces. */
genspace gensp[GENSPACE_COUNT];
/* internal copy of function set(s). */
function_set* fset;
int fset_count;
/* information about each tree--which function set it uses,
its name, size limits, etc. */
treeinfo* tree_map;
int tree_count;
/* maximum number of nodes per individual. -1 if no limit is
enforced. */
int ind_nodelimit;
/* random number generator state */
randomgen globrand;
int main(int argc, char** argv)
{
multipop* mpop;
int startgen;
event start, end, diff;
event eval, breed;
int startfromcheckpoint;
#ifdef MEMORY_LOG
/* dump all memory allocations to a file. */
mlog = fopen ( "memory.log", "w" );
#endif
/* mark the start time, and zero the accumulators for evaluation
and breeding time. */
event_init();
event_mark(&start);
event_zero(&eval);
event_zero(&breed);
if (app_create_output_streams())
error(E_FATAL_ERROR, "app_create_output_streams() failure.");
initialize_output_streams();
/* print copyright message and such. */
initial_message();
/* some initialization. */
oprintf(OUT_SYS, 30, "initialization:\n");
initialize_parameters();
initialize_ephem_const();
initialize_genspace();
/* process the command line. if starting from a checkpoint file, this
function will load the population. */
startfromcheckpoint = process_commandline(argc, argv, &startgen, &mpop);
/* open the files associated with each stream. */
open_output_streams();
/* make internal copies of function set(s), if it hasn't already been
done. */
if (!startfromcheckpoint)
if (app_build_function_sets())
error(E_FATAL_ERROR, "app_build_function_sets() failure.");
/* read parameters limiting tree node count and/or depth. */
read_tree_limits();
/* if not starting from a checkpoint, seed the random number generator. */
if (!startfromcheckpoint)
initialize_random();
#if defined(POSIX_MT) || defined(SOLARIS_MT)
/* setup for multi-threading if applicable */
initialize_threading();
#endif
if (app_initialize(startfromcheckpoint))
error(E_FATAL_ERROR, "app_initialize() failure.");
/* if not starting from a checkpoint, create a random population. */
if (!startfromcheckpoint)
mpop = initial_multi_population();
/* build the breeding table and the subpop exchange table from
the parameter database. */
initialize_topology(mpop);
initialize_breeding(mpop);
/* do the GP. */
run_gp(mpop, startgen, &eval, &breed, startfromcheckpoint);
/* free app stuff. */
app_uninitialize();
/* free lots of stuff. */
free_breeding(mpop);
free_topology(mpop);
free_multi_population(mpop);
free_parameters();
free_ephem_const();
free_genspace();
free_function_sets();
/* mark the finish time. */
event_mark(&end);
event_diff(&diff, &start, &end);
/* print memory/time statistics and close output files. */
output_system_stats(&diff, &eval, &breed);
close_output_streams();
#ifdef MEMORY_LOG
fclose ( mlog );
#endif
/* destroy global random structure */
random_destroy(&globrand);
/* all done. */
return 0;
}
/* function_sets_init()
*
* this function is called from user code and passed the function sets
* and tree maps and names. it makes internal copies and does some
* validation.
*/
int function_sets_init(function_set* user_fset, int user_fcount,
user_treeinfo* user_tree_map, int user_tcount)
{
int i, j, k, m, n, p;
int x;
int errors = 0;
function* cur;
/* Strongly Typed... */
int pos[NUMTYPES]; /* Current position to place a function/terminal in the cset by type */
/* allocate internal copies. */
fset = (function_set*) MALLOC(user_fcount * sizeof(function_set));
tree_map = (treeinfo*) MALLOC(user_tcount * sizeof(treeinfo));
fset_count = user_fcount;
tree_count = user_tcount;
oprintf(OUT_SYS, 30, "updating function set(s):\n");
/* Updates the function set based on input file */
for (i = 0; i < fset_count; ++i)
{
oprintf(OUT_SYS, 30, " set %d:", i);
fset_update(&user_fset[i]);
}
oprintf(OUT_SYS, 30, "building function set(s):\n");
/* for each set of functions... */
for (i = 0; i < fset_count; ++i)
{
/* Initialize counts */
for (x = 0; x < NUMTYPES; x++)
{
fset[i].function_count_by_type[x] = 0;
fset[i].terminal_count_by_type[x] = 0;
fset[i].cset_by_type[x] = (function*) MALLOC(user_fset[i].size * sizeof(function));
pos[x] = 0;
}
oprintf(OUT_SYS, 30, " set %d:", i);
/* allocate memory for the set. */
m = user_fset[i].size;
fset[i].cset = (function*) MALLOC(m * sizeof(function));
fset[i].num_args = 0;
k = 0;
/* Strong Typing: determine number of functions by type */
for (j = 0; j < m; ++j)
{
if (user_fset[i].cset[j].type == FUNC_DATA ||
user_fset[i].cset[j].type == FUNC_EXPR ||
user_fset[i].cset[j].type == EVAL_DATA ||
user_fset[i].cset[j].type == EVAL_EXPR) /* non-terminals */
{
fset[i].function_count_by_type[user_fset[i].cset[j].return_type]++;
} else fset[i].terminal_count_by_type[user_fset[i].cset[j].return_type]++;
}
for (j = 0; j < m; ++j)
{
if (user_fset[i].cset[j].type == FUNC_DATA ||
user_fset[i].cset[j].type == FUNC_EXPR ||
user_fset[i].cset[j].type == EVAL_DATA ||
user_fset[i].cset[j].type == EVAL_EXPR)
{
/** functions and evaluation tokens **/
cur = &(fset[i].cset[k]);
/* copy some stuff over. */
cur->code = user_fset[i].cset[j].code;
cur->ephem_gen = user_fset[i].cset[j].ephem_gen;
cur->ephem_str = user_fset[i].cset[j].ephem_str;
cur->arity = user_fset[i].cset[j].arity;
cur->type = user_fset[i].cset[j].type;
cur->evaltree = user_fset[i].cset[j].evaltree;
/* copy the name string. */
n = strlen(user_fset[i].cset[j].string);
cur->string = (char*) MALLOC(n + 1);
for (p = 0; p < n; ++p)
{
if (isspace(user_fset[i].cset[j].string[p]) ||
user_fset[i].cset[j].string[p] == ':' ||
user_fset[i].cset[j].string[p] == ')' ||
user_fset[i].cset[j].string[p] == '(' ||
user_fset[i].cset[j].string[p] == '[' ||
user_fset[i].cset[j].string[p] == ']')
{
error(E_WARNING, "illegal character(s) in function name changed to '_'.");
cur->string[p] = '_';
} else
cur->string[p] = user_fset[i].cset[j].string[p];
}
cur->string[n] = 0;
/* fill in the index field with this function's position in the
set. */
cur->index = k;
/* the ERC-related fields should be NULL. */
if (cur->ephem_gen || cur->ephem_str)
{
++errors;
error(E_ERROR, "function has non-NULL ephem_gen and/or ephem_str field(s).");
}
/* do some type-specific checking. */
switch (cur->type)
{
case FUNC_DATA:
case FUNC_EXPR:
if (cur->code == NULL)
{
++errors;
error(E_ERROR, "ordinary function has NULL code field.");
}
if (cur->arity < 1)
{
++errors;
error(E_ERROR, "ordinary function has arity of %d.",
cur->arity);
}
if (cur->evaltree != -1)
{
error(E_WARNING, "ordinary function has evaltree field of %d; this will be ignored.", cur->evaltree);
}
break;
case EVAL_DATA:
case EVAL_EXPR:
if (cur->code != NULL)
{
++errors;
error(E_ERROR, "eval function function has non-NULL code field.");
}
if (cur->arity != -1)
{
error(E_WARNING, "eval function has arity field of %d; this will be ignored.", cur->arity);
}
if (cur->evaltree < 0 ||
cur->evaltree >= tree_count)
/* evaluation token refers to a tree that doesn't exist. */
error(E_FATAL_ERROR, "eval function refers to nonexistent tree (%d).", cur->evaltree);
break;
default:
++errors;
error(E_ERROR, "unknown function type %d.", cur->type);
}
/* strong typing...*/
cur->return_type = user_fset[i].cset[j].return_type;
for (x = 0; x < cur->arity; x++)
{
cur->argument_type[x] = user_fset[i].cset[j].argument_type[x];
}
(fset[i].cset_by_type[cur->return_type])[pos[cur->return_type]++] = *cur;
++k;
} else if (user_fset[i].cset[j].type == TERM_NORM ||
user_fset[i].cset[j].type == TERM_ERC ||
user_fset[i].cset[j].type == TERM_ARG)
{
/** terminals (all kinds). **/
/* "cur" is so much easier to type. :) */
cur = &(fset[i].cset[k]);
/* copy stuff. */
cur->code = user_fset[i].cset[j].code;
cur->ephem_gen = user_fset[i].cset[j].ephem_gen;
cur->ephem_str = user_fset[i].cset[j].ephem_str;
cur->arity = user_fset[i].cset[j].arity;
cur->type = user_fset[i].cset[j].type;
cur->evaltree = user_fset[i].cset[j].evaltree;
/* copy terminal name. */
n = strlen(user_fset[i].cset[j].string);
cur->string = (char*) MALLOC(n + 1);
strcpy(cur->string, user_fset[i].cset[j].string);
cur->string[n] = 0;
/* fill in the index field. */
cur->index = k;
if (cur->arity != 0)
{
++errors;
error(E_ERROR, "terminal has nonzero arity.");
}
/* check for correctness of type-dependent fields. */
switch (cur->type)
{
case TERM_NORM:
if (cur->code == NULL)
{
++errors;
error(E_ERROR, "normal terminal has NULL code field.");
}
if (cur->ephem_gen != NULL || cur->ephem_str != NULL)
{
++errors;
error(E_ERROR, "normal terminal has non-NULL ephem_gen and/or ephem_str field(s).");
}
if (cur->evaltree != -1)
{
error(E_WARNING, "normal terminal has evaltree field of %d; this will be ignored.");
}
break;
case TERM_ERC:
if (cur->code != NULL)
{
++errors;
error(E_ERROR, "ERC terminal has non-NULL code field.");
}
if (cur->ephem_gen == NULL || cur->ephem_str == NULL)
{
++errors;
error(E_ERROR, "ERC terminal has NULL ephem_hen and/or ephem_str field(s).");
}
if (cur->evaltree != -1)
{
error(E_WARNING, "ERC terminal has evaltree field of %d; this will be ignored.");
}
break;
case TERM_ARG:
++fset[i].num_args;
if (cur->code != NULL)
{
++errors;
error(E_ERROR, "argument terminal has non-NULL code field.");
}
if (cur->ephem_gen != NULL || cur->ephem_str != NULL)
{
++errors;
error(E_ERROR, "argument terminal has non-NULL ephem_hen and/or ephem_str field(s).");
}
if (cur->evaltree < 0)
{
++errors;
error(E_ERROR, "argument terminal should have nonnegative evaltree field.");
}
break;
}
/* strong typing...*/
cur->return_type = user_fset[i].cset[j].return_type;
(fset[i].cset_by_type[cur->return_type])
[pos[cur->return_type]++] = *cur;
++k;
}
oputs(OUT_SYS, 30, " ");
oputs(OUT_SYS, 30, fset[i].cset[k - 1].string);
}
fset[i].size = k;
oputs(OUT_SYS, 30, "\n");
}
/* if there were any errors, stop now. */
if (errors)
{
error(E_FATAL_ERROR, "error(s) occurred while processing function set(s).");
}
/* build the internal tree map. */
for (i = 0; i < tree_count; ++i)
{
/* the function set used for this tree. */
tree_map[i].fset = user_tree_map[i].fset;
if (tree_map[i].fset < 0 || tree_map[i].fset >= fset_count)
error(E_FATAL_ERROR, "tree %d uses a nonexistent function set.\n", i);
tree_map[i].return_type = user_tree_map[i].return_type;
if (tree_map[i].return_type < 0 || tree_map[i].return_type >= NUMTYPES)
error(E_FATAL_ERROR, "tree %d uses an invalid return type: %d.\n", i,
tree_map[i].return_type);
oprintf(OUT_SYS, 30, " tree %d uses function set %d.\n", i, tree_map[i].fset);
/* these will be filled in by read_tree_limits(). */
tree_map[i].nodelimit = -1;
tree_map[i].depthlimit = -1;
/* copy the tree name. */
j = strlen(user_tree_map[i].name);
tree_map[i].name = (char*) MALLOC((j + 1) * sizeof(char));
strcpy(tree_map[i].name, user_tree_map[i].name);
}
/* now some more processing on each function set. */
for (i = 0; i < fset_count; ++i)
{
fset[i].function_count = 0;
fset[i].terminal_count = 0;
for (j = 0; j < fset[i].size; ++j)
{
if (fset[i].cset[j].arity == -1)
{
/* change the arity of evaluation tokens from -1
to the number of argument tokens in the called tree. */
fset[i].cset[j].arity = fset[tree_map[fset[i].cset[j].evaltree].fset].num_args;
if (fset[i].cset[j].arity == 0)
/* if there are no argument tokens in the tree,
mark this as a terminal. */
fset[i].cset[j].type = EVAL_TERM;
}
/* update count of functions and terminals. */
if (fset[i].cset[j].arity)
++fset[i].function_count;
else
++fset[i].terminal_count;
}
/* now sort the function set so that all the functions
come first. */
qsort(fset[i].cset, fset[i].size, sizeof(function),
function_compare);
for (x = 0; x < NUMTYPES; x++)
{
qsort(fset[i].cset_by_type[x], fset[i].function_count_by_type[x] +
fset[i].terminal_count_by_type[x], sizeof(function),
function_compare);
}
}
#ifdef DEBUG
/* dump the function sets to stdout. */
for ( i = 0; i < fset_count; ++i )
{
printf ( "FUNCTION SET %d\n", i );
printf ( " %d functions; %d terminals; %d arguments\n",
fset[i].function_count, fset[i].terminal_count,
fset[i].num_args );
for ( j = 0; j < fset[i].size; ++j )
printf ( "%10s %06x %06x %06x arity: %3d evaltree: %3d index: %3d type: %3d\n",
fset[i].cset[j].string,
fset[i].cset[j].code,
fset[i].cset[j].ephem_gen,
fset[i].cset[j].ephem_str,
fset[i].cset[j].arity,
fset[i].cset[j].evaltree,
fset[i].cset[j].index,
fset[i].cset[j].type );
}
#endif
oprintf(OUT_SYS, 30, " function set complete.\n");
return 0;
}
/* function_compare()
*
* comparison function for qsort() that puts all functions ahead of
* all terminals.
*/
int function_compare(const void* a, const void* b)
{
int aa, ba;
aa = !!(((function*) a)->arity);
ba = !!(((function*) b)->arity);
return ba - aa;
}
/* free_function_sets()
*
* free up internal copies of function sets and tree maps.
*/
void free_function_sets(void)
{
int i, j;
for (i = 0; i < fset_count; ++i)
{
for (j = 0; j < fset[i].function_count + fset[i].terminal_count; ++j)
FREE(fset[i].cset[j].string);
FREE(fset[i].cset);
/* Strong Typing */
for (j = 0; j < NUMTYPES; ++j)
{
FREE(fset[i].cset_by_type[j]);
}
}
FREE(fset);
for (i = 0; i < tree_count; ++i)
FREE(tree_map[i].name);
FREE(tree_map);
fset = NULL;
tree_map = NULL;
}
/* read_tree_limits()
*
* read limits on tree node count and/or depth from the parameter
* database and fill in the appropriate fields of the tree_map
* array.
*/
void read_tree_limits(void)
{
int i, j;
char pnamebuf[100];
char* param;
for (i = 0; i < tree_count; ++i)
{
/* read the node limit for this tree. */
sprintf(pnamebuf, "tree[%d].max_nodes", i);
param = get_parameter(pnamebuf);
if (param == NULL)
tree_map[i].nodelimit = -1;
else
tree_map[i].nodelimit = atoi(param);
/* read the depth limit for this tree. */
sprintf(pnamebuf, "tree[%d].max_depth", i);
param = get_parameter(pnamebuf);
if (param == NULL)
tree_map[i].depthlimit = -1;
else
tree_map[i].depthlimit = atoi(param);
}
/* read the node limit for the whole individual. */
param = get_parameter("max_nodes");
if (param == NULL)
ind_nodelimit = -1;
else
ind_nodelimit = atoi(param);
/* read the depth limit for the whole individual. note that
this is implemented just as a cap on the maximum depth of
any single tree in the individual. */
param = get_parameter("max_depth");
if (param)
{
j = atoi(param);
if (j >= 0)
for (i = 0; i < tree_count; ++i)
if (tree_map[i].depthlimit < 0 ||
tree_map[i].depthlimit > j)
tree_map[i].depthlimit = j;
}
}
/* initialize_random()
*
* initialize the random number generator.
*/
void initialize_random(void)
{
char* param;
char seedstr[30];
int seed;
/* look for a seed parameter. */
param = get_parameter("random_seed");
if (param == NULL)
{
sprintf(seedstr, "%d", 1);
/* if it's not found... */
#ifdef RANDOMSEEDTIME
FILE* RANDOM_FILE = fopen("/dev/urandom", "r");
char buffer[4];
fgets(buffer, 4, RANDOM_FILE);
int tm = (int) time(NULL);
/* ...use the current time. */
if (buffer[0] == 0)
buffer[0] = 1;
if (buffer[1] == 0)
buffer[1] = 1;
if (buffer[2] == 0)
buffer[2] = 1;
seed = (tm % buffer[0]) * (tm % buffer[1]) + ((tm % buffer[2]) << buffer[3] % 31);
sprintf(seedstr, "%d", seed);
add_parameter("random_seed", seedstr, PARAM_COPY_VALUE);
fclose(RANDOM_FILE);
#else
/* ...use 1. */
seed = 1;
add_parameter ( "random_seed", seedstr, PARAM_COPY_NONE);
#endif
/* print out what we're using. */
oprintf(OUT_SYS, 20,
" no random number seed specfied; using %d.\n",
seed);
} else
{
/* the parameter was found; use it. */
seed = atoi(param);
oprintf(OUT_SYS, 20,
" seeding random number generator with %d.\n",
seed);
}
random_seed(&globrand, seed);
}
/* pre_parameter_defaults()
*
* used to place values into the parameter database before any application
* code is called or any command line options are processed.
*/
void pre_parameter_defaults(void)
{
add_parameter("output.basename", "lilgp", PARAM_COPY_NONE);
add_parameter("output.stt_interval", "1", PARAM_COPY_NONE);
add_parameter("output.detail", "50", PARAM_COPY_NONE);
add_parameter("output.bestn", "1", PARAM_COPY_NONE);
add_parameter("output.digits", "4", PARAM_COPY_NONE);
add_parameter("init.method", "half_and_half",
PARAM_COPY_NONE);
add_parameter("init.depth", "2-6", PARAM_COPY_NONE);
add_parameter("init.random_attempts", "100", PARAM_COPY_NONE);
add_parameter("checkpoint.filename", "gp%06d.ckp",
PARAM_COPY_NONE);
/* default problem uses a single population. */
add_parameter("multiple.subpops", "1", PARAM_COPY_NONE);
}
/* post_parameter_defaults()
*
* add/change values in the parameter database after all command line options
* are parsed. can be used to set defaults based on values of other
* parameters.
*/
void post_parameter_defaults(void)
{
binary_parameter("probabilistic_operators", 1);
}
/* process_commandline()
*
* parses the command line.
*/
int process_commandline(int argc, char** argv, int* gen,
multipop** mpop)
{
int i;
int errorflag = 0;
int startfromcheckpoint = 0;
*mpop = NULL;
*gen = 0;
/* if there are no arguments, print out a brief statement of usage
and exit. */
if (argc < 2)
{
fprintf(stderr, "usage: %s options\nValid options are:\n", argv[0]);
fprintf(stderr, " [-f parameterfile] read named parameter file\n");
fprintf(stderr, " [-c checkpointfile] restart from name checkpoint file\n");
fprintf(stderr, " [-p name=value] set parameter name to value\n");
fprintf(stderr, " [-q] run in quiet mode\n");
fprintf(stderr, " [-d symbol] define symbol\n");
fprintf(stderr, " [-u symbol] undefine symbol\n");
exit(1);
}
/* load hardcoded defaults into database. */
pre_parameter_defaults();
for (i = 1; i < argc; ++i)
{
/* all options begin with '-' and have two characters,
except "-d" and "-u" which may have more. */
if (argv[i][0] != '-' || (argv[i][1] != 'd' && argv[i][1] != 'u' && argv[i][2] != 0))
{
error(E_ERROR, "unrecognized command line option: \"%s\".",
argv[i]);
errorflag = 1;
continue;
}
switch (argv[i][1])
{
case 'f':
/* load a parameter file, named in the next argument. */
read_parameter_file(argv[++i]);
break;
case 'p':
/* parse a single parameter, in the next argument. */
if (parse_one_parameter(argv[++i]))
{
errorflag = 1;
error(E_ERROR, "malformed parameter: \"%s\".", argv[i]);
}
break;
case 'c':
/* load a checkpoint file, named in the next argument. */
if (startfromcheckpoint)
{
/* error if a checkpoint has already been loaded. */
error(E_ERROR, "can't load multiple checkpoint files.");
errorflag = 1;
continue;
}
read_checkpoint(argv[++i], gen, mpop);
startfromcheckpoint = 1;
break;
case 'q':
/* turn on quiet mode (don't dup OUT_SYS to stdout). */
quietmode = 1;
break;
case 'd':
/* define a symbol. */
if (argv[i][2])
/* of the form "-dsymbol". */
define_directive(argv[i] + 2);
else
/* of the form "-d symbol". */
define_directive(argv[++i]);
break;
case 'u':
/* undefine a symbol. */
if (argv[i][2])
/* of the form "-usymbol". */
undefine_directive(argv[i] + 2);
else
/* of the form "-u symbol". */
undefine_directive(argv[++i]);
break;
default:
error(E_ERROR, "unrecognized command line option: \"%s\".",
argv[i]);
errorflag = 1;
break;
}
}
if (errorflag)
error(E_FATAL_ERROR, "command line errors occurred. dying.");
if (!startfromcheckpoint)
post_parameter_defaults();
return startfromcheckpoint;
}
/* output_system_stats()
*
* print statistics about memory use, execution time, etc. to OUT_SYS
* at conclusion of run.
*/
void output_system_stats(event* t_total, event* t_eval, event* t_breed)
{
int total, free, max, mallocc, reallocc, freec;
int ercused, ercfree, ercblocks, ercalloc;
int i;
get_ephem_stats(&ercused, &ercfree, &ercblocks, &ercalloc);
oprintf(OUT_SYS, 30, "\nSYSTEM STATISTICS\n");
#ifdef TRACK_MEMORY
/* if memory tracking available, then get and print the numbers. */
get_memory_stats(&total, &free, &max, &mallocc, &reallocc, &freec);
oprintf(OUT_SYS, 30, "\n------- memory -------\n");
oprintf(OUT_SYS, 30, " allocated: %d\n", total);
oprintf(OUT_SYS, 30, " freed: %d\n", free);
oprintf(OUT_SYS, 30, " not freed: %d\n", total - free);
oprintf(OUT_SYS, 30, " max allocated: %d\n", max);
oprintf(OUT_SYS, 30, " malloc'ed blocks: %d\n", mallocc);
oprintf(OUT_SYS, 30, " realloc'ed blocks: %d\n", reallocc);
oprintf(OUT_SYS, 30, " free'ed blocks: %d\n", freec);
#endif
#ifdef TIMING_AVAILABLE
/* if timing is available, the get and print the numbers. */
oprintf(OUT_SYS, 30, "\n------- time -------\n");
oprintf(OUT_SYS, 30, " overall: %s\n",
event_string(t_total));
oprintf(OUT_SYS, 30, " evaluation: %s\n",
event_string(t_eval));
oprintf(OUT_SYS, 30, " breeding: %s\n",
event_string(t_breed));
#endif
/* show how large the generation spaces grew. */
oprintf(OUT_SYS, 30, "\n------- generation spaces -------\n");
for (i = 0; i < GENSPACE_COUNT; ++i)
oprintf(OUT_SYS, 30, " space %3d size: %d\n",
i, gensp[i].size);
/* if any ERCs were used, then show these stats. */
if (ercused > 0)
{
oprintf(OUT_SYS, 30, "\n------- ephemeral random constants -------\n");
oprintf(OUT_SYS, 30, " used: %d\n", ercused);
oprintf(OUT_SYS, 30, " freed: %d\n", ercfree);
oprintf(OUT_SYS, 30, " allocated: %d\n", ercalloc);
oprintf(OUT_SYS, 30, " blocks: %d\n", ercblocks);
}
}
/* initial_message()
*
* show startup and copyright messages.
*/
void initial_message(void)
{
oputs(OUT_SYS, 0,
"\n[ lil-gp Genetic Programming System.\n");
oputs(OUT_SYS, 0,
"[ Portions copyright (c) 1995 Michigan State University. All rights reserved.\n");
oputs(OUT_SYS, 0,
"[ kernel version 1.0; 11 July 1995.\n\n\n");
}