COSC_4P82_Assignment_1/lib/lilgp/kernel/populate.c

549 lines
14 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>
/* Read in an individual from a file, skipping any text in between */
void mod_read_tree_recurse ( int space, ephem_const **eind, FILE *fil, int tree,
char *string, int skip )
{
function *f;
int i, j;
ephem_const *ep;
if( skip )
{
i = 0;
/*Read up until we get the first parenthesies */
while( i != '(' )
{
if( feof(fil) )
{
fseek( fil, 0L, SEEK_SET );
}
i = fgetc(fil);
}
if( i != '(' )
{
error( E_FATAL_ERROR, "Ran out of file space while reading in saved tree");
}
}
/* read up until a nonwhitespace character in file. the nonwhitespace
character is saved in string[0]. */
while ( isspace(string[0]=fgetc(fil)) );
/* get the next character. */
i = fgetc ( fil );
if ( isspace(i) )
/* if the next character is whitespace, then string[0] is a
one-character function name. null-terminate the string. */
string[1] = 0;
else
{
/** if the next character is not whitespace, then string[0]
is either an open parenthesis or the first character of a
multi-character function name. **/
/* push the next character back. */
ungetc ( i, fil );
/* read the function name. skip over an open parenthesis, if there
is one. */
fscanf ( fil, "%s ", string+(string[0]!='(') );
}
#ifdef DEBUG_READTREE
fprintf ( stderr, "function name is [%s]\n", string );
#endif
/* look up the function name in this tree's function set. if the
function is an ERC terminal (the name is of the form "name:ERCindex"),
then place the ERC address in ep. */
f = get_function_by_name ( tree, string, &ep, eind );
/* add an lnode to the tree. */
gensp_next(space)->f = f;
switch ( f->type )
{
case TERM_NORM:
case TERM_ARG:
case EVAL_TERM:
break;
case TERM_ERC:
/* record the ERC address as the next lnode in the array. */
gensp_next(space)->d = ep;
break;
case FUNC_DATA:
case EVAL_DATA:
/** recursively read child functions, no skip nodes needed. **/
for ( i = 0; i < f->arity; ++i )
mod_read_tree_recurse ( space, eind, fil, tree, string, 0 );
break;
case FUNC_EXPR:
case EVAL_EXPR:
/** recursively read child functions, recording skip values. **/
for ( i = 0; i < f->arity; ++i )
{
/* save an lnode for the skip value. */
j = gensp_next_int ( space );
/* read the child tree. */
mod_read_tree_recurse ( space, eind, fil, tree, string, 0);
/* figure out how big the child tree was, and save that
number in the skip node. */
gensp[space].data[j].s = gensp[space].used-j-1;
}
break;
}
}
/* generate_random_population()
*
* fills a population with randomly generated members.
*/
void generate_random_population ( population *p, int *mindepth,
int *maxdepth, int *method, FILE **dataum )
{
int i, j, k, m;
int attempts;
int totalattempts = 0;
int depth;
int attempts_generation;
tree *temp;
int totalnodes = 0;
int flag;
char buf[2048];
int ignore_limits;
/* how many consecutive rejected trees we will tolerate before
giving up. */
attempts_generation = atoi ( get_parameter ( "init.random_attempts" ) );
if ( attempts_generation <= 0 )
error ( E_FATAL_ERROR,
"\"init.random_attempts\" must be positive." );
ignore_limits = (get_parameter("init.ignore_limits")!=NULL);
temp = (tree *)MALLOC ( tree_count * sizeof ( tree ) );
k = 0;
attempts = attempts_generation;
while ( k < p->size )
{
/* total nodes in the individual being generated. */
totalnodes = 0;
for ( j = 0; j < tree_count; ++j )
{
if ( attempts <= 0 )
error ( E_FATAL_ERROR,
"The last %d trees generated have been bad. Giving up.",
attempts_generation );
--attempts;
++totalattempts;
/* pick a depth on the depth ramp. */
depth = mindepth[j] + random_int ( &globrand, maxdepth[j] - mindepth[j] + 1 );
/* clear a generation space. */
gensp_reset ( 0 );
/** generate the tree. **/
switch ( method[j] )
{
case GENERATE_FULL:
generate_random_full_tree ( 0, depth, fset+tree_map[j].fset,
tree_map[j].return_type);
break;
case GENERATE_GROW:
generate_random_grow_tree ( 0, depth, fset+tree_map[j].fset,
tree_map[j].return_type);
break;
case GENERATE_HALF_AND_HALF:
if ( random_double(&globrand) < 0.5 )
generate_random_full_tree ( 0, depth, fset+tree_map[j].fset,
tree_map[j].return_type);
else
generate_random_grow_tree ( 0, depth, fset+tree_map[j].fset,
tree_map[j].return_type);
break;
case LOAD_FILE:
gensp_reset(0);
mod_read_tree_recurse( 0, NULL, dataum[j], j, buf, 1);
/* need to do something here about limit checking */
break;
}
/** throw away the tree if it's too big. **/
/*printf("Attempted Tree: ");
print_tree(gensp[0].data,stdout);*/
/* first check the node limits. */
flag = 0;
m = tree_nodes ( gensp[0].data );
if (method[j]!=LOAD_FILE)
{
if ( tree_map[j].nodelimit > -1 && m > tree_map[j].nodelimit )
{
--j;
continue;
}
/* now change the depth limits. */
if ( tree_map[j].depthlimit > -1 && tree_depth ( gensp[0].data ) > tree_map[j].depthlimit )
{
--j;
continue;
}
/* count total nodes in the individual being created. */
}
totalnodes += m;
gensp_dup_tree ( 0, temp+j );
}
if (!ignore_limits)
{
/* is the individual over the total node limit (if one is set)? */
if ( ind_nodelimit > -1 && totalnodes > ind_nodelimit )
{
#ifdef DEBUG
printf ( "overall node limit violated.\n" );
#endif
/* yes, so delete it and try again. */
for ( j = 0; j < tree_count; ++j )
free_tree ( temp+j );
continue;
}
/* throw away the individual if it's a duplicate. */
for ( i = 0; i < k; ++i )
{
flag = 0;
for ( j = 0; j < tree_count && !flag; ++j )
{
if ( temp[j].size == p->ind[i].tr[j].size )
{
if ( memcmp ( temp[j].data, p->ind[i].tr[j].data,
temp[j].size * sizeof ( lnode ) ) )
{
flag = 1;
}
}
else
flag = 1;
}
if ( !flag )
break;
}
if ( i < k )
{
#ifdef DEBUG
printf ( "duplicate individual: (same as %d)\n", i );
for ( j = 0; j < tree_count; ++j )
{
printf ( " tree %d: ", j );
print_tree ( temp[j].data, stdout );
}
#endif
/* individual is a duplicate, throw it away. */
--attempts;
for ( j = 0; j < tree_count; ++j )
free_tree ( temp+j );
continue;
}
}
/** we now have a good individual to put in the population. */
/* copy the tree array. */
memcpy ( p->ind[k].tr, temp, tree_count * sizeof ( tree ) );
/* reference ERCs. */
for ( j = 0; j < tree_count; ++j )
reference_ephem_constants ( p->ind[k].tr[j].data, 1 );
#ifdef DUMP_POPULATION
printf ( "individual %5d:\n", k );
print_individual ( p->ind+k, stdout );
#endif
/* mark individual as unevaluated. */
p->ind[k].evald = EVAL_CACHE_INVALID;
p->ind[k].flags = FLAG_NONE;
attempts = attempts_generation;
++k;
}
FREE ( temp );
oprintf ( OUT_SYS, 10,
" %d trees were generated to fill the population of %d (%d trees).\n",
totalattempts, p->size, p->size * tree_count );
}
/* allocate_population()
*
* allocates a population structure with the given size.
*/
population *allocate_population ( int size )
{
int i;
population *p = (population *)MALLOC ( sizeof ( population ) );
p->size = size;
p->next = 0;
/* allocate the array of individuals. */
p->ind = (individual *)MALLOC ( size * sizeof ( individual ) );
for ( i = 0; i < size; ++i )
{
/* each individual has a block of tree structures, allocate
those here. */
p->ind[i].tr = (tree *)MALLOC ( tree_count * sizeof ( tree ) );
p->ind[i].evald = EVAL_CACHE_INVALID;
p->ind[i].flags = FLAG_NONE;
}
return p;
}
/* free_multi_population()
*
* frees the populations in a multipop structure.
*/
void free_multi_population ( multipop *mp )
{
int i;
for ( i = 0; i < mp->size; ++i )
free_population ( mp->pop[i] );
FREE ( mp->pop );
FREE ( mp );
}
/* free_population()
*
* frees a population and all the individuals in it.
*/
void free_population ( population *p )
{
int i, j;
for ( i = 0; i < p->size; ++i )
{
for ( j = 0; j < tree_count; ++j )
{
/* dereference ERCs. */
reference_ephem_constants ( p->ind[i].tr[j].data, -1 );
free_tree ( &(p->ind[i].tr[j]) );
}
FREE ( p->ind[i].tr );
}
FREE ( p->ind );
FREE ( p );
}
/* initial_multi_population()
*
* randomly fills a multipop strcture with individuals.
*/
multipop *initial_multi_population ( void )
{
char *param;
char temp_name[256];
char **tree_replace;
multipop *mpop;
int i;
int *mindepth, *maxdepth, *method;
char *cp;
char pnamebuf[100];
FILE **tree_data;
FILE *fp;
oputs ( OUT_SYS, 10, "creating initial population(s):\n" );
mpop = (multipop *)MALLOC ( sizeof ( multipop ) );
/* how many subpops are we supposed to have? */
param = get_parameter ( "multiple.subpops" );
mpop->size = atoi ( param );
if ( mpop->size <= 0 )
error ( E_FATAL_ERROR,
"\"%s\" is not a valid value for \"multiple.subpops\".",
param );
/* allocate that many population pointers. */
mpop->pop = (population **)MALLOC ( sizeof ( population* ) * mpop->size );
/* read the depth ramp and generation method(s), which can be
different for each tree. */
tree_replace = (char **)MALLOC(sizeof(char *)*tree_count);
tree_data = (FILE **)MALLOC( sizeof(FILE *)*tree_count);
for( i = 0; i < tree_count; i++ )
{
sprintf( temp_name, "tree-replace[%d]", i );
tree_replace[i] = get_parameter( temp_name );
}
for( i = 0; i < tree_count; i++ )
{
if( tree_replace[i] != NULL )
{
tree_data[i] = fopen( tree_replace[i], "r" );
if( fp == NULL )
{
/* Error Handler */
error( E_FATAL_ERROR, "Unable to open file %s\n", tree_replace[i] );
}
} else {
tree_data[i] = NULL;
}
}
mindepth = (int *)MALLOC ( tree_count * sizeof ( int ) );
maxdepth = (int *)MALLOC ( tree_count * sizeof ( int ) );
method = (int *)MALLOC ( tree_count * sizeof ( int ) );
for ( i = 0; i < tree_count; ++i )
{
mindepth[i] = -1;
maxdepth[i] = -1;
/** read the depth ramp. **/
sprintf ( pnamebuf, "init.tree[%d].depth", i );
param = get_parameter ( pnamebuf );
if ( !param )
param = get_parameter ( "init.depth" );
if ( param == NULL )
error ( E_FATAL_ERROR, "\"init.tree[%d].depth\" must be specified.", i );
/** parse the depth ramp ("min-max" or just "val"). **/
mindepth[i] = strtol ( param, &cp, 10 );
if ( *cp )
{
if ( *cp == '-' )
{
maxdepth[i] = strtol ( cp+1, &cp, 10 );
}
if ( *cp )
{
error ( E_FATAL_ERROR, "\"init.tree[%d].depth\" is malformed.",
i );
}
}
if ( maxdepth[i] == -1 )
maxdepth[i] = mindepth[i];
if ( mindepth[i] > maxdepth[i] )
error ( E_FATAL_ERROR, "\"init.tree[%d].depth\" is malformed.", i );
/** read the method. **/
sprintf ( pnamebuf, "init.tree[%d].method", i );
param = get_parameter ( pnamebuf );
if ( !param )
param = get_parameter ( "init.method" );
if ( param == NULL )
error ( E_FATAL_ERROR, "\"init.tree[%d].method\" must be set.",
i );
if ( strcmp ( param, "half_and_half" ) == 0 )
method[i] = GENERATE_HALF_AND_HALF;
else if ( strcmp ( param, "full" ) == 0 )
method[i] = GENERATE_FULL;
else if ( strcmp ( param, "grow" ) == 0 )
method[i] = GENERATE_GROW;
else if ( strcmp ( param, "load" ) == 0 )
method[i]= LOAD_FILE;
else
error ( E_FATAL_ERROR, "\"init.tree[%d].method\": \"%s\" is not a known generation method.",
i, param );
}
/* generate each population. */
for ( i = 0; i < mpop->size; ++i )
mpop->pop[i] = initial_population ( mindepth, maxdepth, method, tree_data );
for( i = 0; i < tree_count; i++ )
{
if( tree_data[i] != NULL )
fclose(tree_data[i]);
}
FREE ( mindepth );
FREE ( maxdepth );
FREE ( method );
FREE ( tree_replace );
FREE ( tree_data );
oputs ( OUT_SYS, 10, " initial population(s) complete.\n" );
return mpop;
}
/* initial_population()
*
* creates a population structure and fills it with randomly
* generated individuals.
*/
population *initial_population ( int *mindepth, int *maxdepth, int *method, FILE **dataum )
{
population *pop;
int pop_size;
char *param;
/* get the population size and allocate. */
param = get_parameter ( "pop_size" );
if ( param == NULL )
error ( E_FATAL_ERROR,
"no value specified for \"pop_size\"." );
pop_size = atoi ( param );
pop = allocate_population ( pop_size );
/* get the generation method and create the random population. */
generate_random_population ( pop, mindepth, maxdepth, method, dataum );
return pop;
}