/* 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 * * This parallel version based on PVM is an extension of version 1.1 * of Lil-gp. * * Johan Parent (johan@info.vub.ac.be) * * Faculty of Applied Sciences (Engineering Faculty) * Building K, Computer Science Department * Vrije Universiteit Brussel * Pleinlaan 2, 1050 Etterbeek * Belgium * */ #include <lilgp.h> /* generate_random_population() * * fills a population with randomly generated members. */ void generate_random_population ( population *p, int *mindepth, int *maxdepth, int *method ) { int i, j, k, m; int attempts; int totalattempts = 0; int depth; int attempts_generation; tree *temp; int totalnodes = 0; int flag; /* 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." ); 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 ( 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() < 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; } /** throw away the tree if it's too big. **/ /* first check the node limits. */ flag = 0; m = tree_nodes ( gensp[0].data ); 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 ); } /* 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; #ifdef _PARALLEL_H p->ind[i].current_exch = -1; p->ind[i].new_trees = 0; #endif } return p; } /* free_multi_population() * * frees the populations in a multipop structure. */ void free_multi_population ( multipop *mp ) { int i; #ifdef _PARALLEL_H int low; int high; low = get_low(); high = get_high(); for ( i = low; i < high; i++ ) #else for ( i = 0; i < mp->size; ++i ) #endif 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 ( int low, int high ) { char *param; multipop *mpop; int i; int *mindepth, *maxdepth, *method; char *cp; char pnamebuf[100]; 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. */ 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 error ( E_FATAL_ERROR, "\"init.tree[%d].method\": \"%s\" is not a known generation method.", i, param ); } /* generate each population. */ for ( i = low; i < high; ++i ) mpop->pop[i] = initial_population ( mindepth, maxdepth, method ); FREE ( mindepth ); FREE ( maxdepth ); FREE ( method ); 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 ) { 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 ); return pop; } #ifdef _PARALLEL_H /* initial_minimal_multi_population() * * randomly fills a multipop strcture with individuals. */ multipop *initial_minimal_multi_population ( void ) { char *param; multipop *mpop; oputs ( OUT_SYS, 10, "creating MINIMAL 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 ); /* Just in order to ease the deallocation... later */ mpop->pop = (population **)MALLOC ( 1 ); if ( mpop->size <= 0 ) error ( E_FATAL_ERROR, "\"%s\" is not a valid value for \"multiple.subpops\".", param ); return mpop; } #endif