897 lines
30 KiB
C
897 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
|
|
/* ...use the current time. */
|
|
seed = time(NULL);
|
|
sprintf(seedstr, "%ld", seed);
|
|
add_parameter ( "random_seed", seedstr, PARAM_COPY_VALUE);
|
|
#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" );
|
|
|
|
}
|