/* 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 popstats *run_stats = NULL; saved_ind *saved_head = NULL; saved_ind *saved_tail; #ifdef _PARALLEL_H int gen; int term = 0; event eval; event breeding; event eval_diff; event breed_diff; #endif /* run_gp() * * the whole enchilada. runs, from generation startgen, using population * mpop. accumulates time spent evaluating and breeding in t_eval and t_breed. */ void run_gp ( multipop *mpop, int startgen, event *t_eval, event *t_breed, int startfromcheckpoint ) { char *param; #ifndef _PARALLEL_H int gen; int term = 0; #else int low; int high; #endif int maxgen; int exch_gen; int i, j; int checkinterval; char *checkfileformat; char *checkfilename = NULL; event start, end, diff; int stt_interval; int bestn; #ifdef _PARALLEL_H exch_gen = -1; #endif if ( !startfromcheckpoint ) { /* get the number of top individuals to track. */ bestn = atoi ( get_parameter ( "output.bestn" ) ); if ( bestn < 1 ) { error ( E_WARNING, "\"output.bestn\" must be at least 1. defaulting to 1." ); bestn = 1; } /* allocate statistics for overall run. */ run_stats = (popstats *)MALLOC ( (mpop->size+1)*sizeof ( popstats ) ); for ( i = 0; i < mpop->size+1; ++i ) { run_stats[i].bestn = bestn; run_stats[i].size = -1; } /* initialize the linked list of saved individuals. */ saved_head = (saved_ind *)MALLOC ( sizeof ( saved_ind ) ); saved_head->ind = NULL; saved_head->refcount = 0; saved_head->next = NULL; saved_tail = saved_head; } /* get the maximum number of generations. */ param = get_parameter ( "max_generations" ); if ( param == NULL ) error ( E_FATAL_ERROR, "no value specified for \"max_generations\"." ); maxgen = atoi ( param ); if ( maxgen <= 0 ) error ( E_FATAL_ERROR, "\"max_generations\" must be greater than zero." ); /* get the interval for subpopulation exchanges, if there is more than one subpopulation. */ if ( mpop->size > 1 ) { param = get_parameter ( "multiple.exch_gen" ); if ( param == NULL ) error ( E_FATAL_ERROR, "no value specified for \"multiple.exch_gen\"." ); exch_gen = atoi ( param ); if ( exch_gen <= 0 ) error ( E_FATAL_ERROR, "\"multiple.exch_gen\" must be greater than zero." ); } /* get the interval for doing checkpointing. */ param = get_parameter ( "checkpoint.interval" ); if ( param == NULL ) /* checkpointing disabled. */ checkinterval = -1; else checkinterval = atoi ( param ); /* get the format string for the checkpoint filenames. */ checkfileformat = get_parameter ( "checkpoint.filename" ); checkfilename = (char *)MALLOC ( strlen ( checkfileformat ) + 50 ); /* get the interval for writing information to the .stt file. */ stt_interval = atoi ( get_parameter ( "output.stt_interval" ) ); if ( stt_interval < 1 ) error ( E_FATAL_ERROR, "\"output.stt_interval\" must be greater than zero." ); oputs ( OUT_SYS, 10, "\n\nstarting evolution.\n" ); /* print out how often we'll be doing checkpointing. */ if ( checkinterval > 0 ) oprintf ( OUT_SYS, 20, "checkpointing will be done every %d generations and "\ "after the last generation.\n", checkinterval ); else if ( checkinterval == 0 ) oprintf ( OUT_SYS, 20, "checkpointing will be done only after the last "\ "generation.\n" ); else oprintf ( OUT_SYS, 20, "no checkpointing will be done.\n" ); /* the big loop. */ for ( gen = startgen; gen <= maxgen && !term; ++gen ) { oprintf ( OUT_SYS, 20, "=== generation %d.\n", gen ); /* unless this is the first generation after loading a checkpoint file... */ if ( ! ( startfromcheckpoint && gen == startgen ) ) { /* evaluate the population. */ event_mark ( &start ); #ifndef _PARALLEL_H for ( i = 0; i < mpop->size; ++i ) #else low = get_low(); high = get_high(); for ( i = low; i < high; ++i ) #endif evaluate_pop ( mpop->pop[i] ); event_mark ( &end ); event_diff ( &diff, &start, &end ); #ifdef _PARALLEL_H eval_diff = diff; #endif #ifdef TIMING_AVAILABLE oprintf ( OUT_SYS, 40, " evaluation complete. (%s)\n", event_string ( &diff ) ); #else oprintf ( OUT_SYS, 40, " evaluation complete.\n" ); #endif event_accum ( t_eval, &diff ); /* calculate and print statistics. returns 1 if user termination criterion was met, 0 otherwise. */ term = generation_information ( gen, mpop, stt_interval, run_stats[0].bestn ); if ( term ) { oprintf ( OUT_SYS, 30, "user termination criterion met.\n" ); #ifdef _PARALLEL_H if (get_operation_mode() == SLAVE) { /* Send termination signal to the master */ signal_master(TERM_CRITERION_TAG); } #endif } flush_output_streams(); } /** write a checkpoint file if checkinterval is non-negative and: we've reached the last generation, or the user termination criterion has been met, or we've reached the specified checkpoint interval. **/ if ( checkinterval >= 0 && (gen == maxgen || term || (checkinterval>0 && gen>startgen && (gen%checkinterval)==0)) ) { sprintf ( checkfilename, checkfileformat, gen ); write_checkpoint ( gen, mpop, checkfilename ); } /** if this is not the last generation and the user criterion hasn't been met, then do breeding. **/ if ( gen != maxgen && !term ) { /** exchange subpops if it's time. **/ if ( mpop->size>1 && gen && (gen%exch_gen)==0 ) { exchange_subpopulations ( mpop ); oprintf ( OUT_SYS, 10, " subpopulation exchange complete.\n" ); } /* breed the new population. */ event_mark ( &start ); #ifndef _PARALLEL_H for ( i = 0; i < mpop->size; ++i ) #else low = get_low(); high = get_high(); for ( i = low; i < high; ++i ) #endif mpop->pop[i] = change_population ( mpop->pop[i], mpop->bpt[i] ); event_mark ( &end ); event_diff ( &diff, &start, &end ); #ifdef _PARALLEL_H breed_diff = diff; #endif /* call the application end-of-breeding callback. */ app_end_of_breeding ( gen, mpop ); #ifdef TIMING_AVAILABLE oprintf ( OUT_SYS, 30, " breeding complete. (%s)\n", event_string ( &diff ) ); #else oprintf ( OUT_SYS, 30, " breeding complete.\n" ); #endif event_accum ( t_breed, &diff ); } /* free unused ERCs. */ ephem_const_gc(); flush_output_streams(); } /** free up a lot of stuff before returning. */ if ( checkfilename ) FREE ( checkfilename ); ephem_const_gc(); #ifndef _PARALLEL_H for ( i = 0; i < mpop->size+1; ++i ) { for ( j = 0; j < run_stats[i].bestn; ++j ) --run_stats[i].best[j]->refcount; FREE ( run_stats[i].best ); } #else low = get_low(); high = get_high(); /* We used only a part of the stats */ for ( i = low+1; i < high+1; ++i ) { if (run_stats[i].best) { for ( j = 0; j < run_stats[i].bestn; ++j ) --run_stats[i].best[j]->refcount; FREE ( run_stats[i].best ); } } /* Last but not least */ for ( j = 0; j < run_stats[0].bestn; ++j ) --run_stats[0].best[j]->refcount; FREE ( run_stats[0].best ); #endif FREE ( run_stats ); saved_individual_gc(); FREE ( saved_head ); #ifdef _PARALLEL_H if (get_operation_mode() == SLAVE) { /* Send termination signal to the master */ signal_master(TERM_ENDED_TAG); } #endif } /* generation_information() * * calculates and prints population statistics. */ int generation_information ( int gen, multipop *mpop, int stt_interval, int bestn ) { int i, j; int newbest; static int fd = -1; popstats *gen_stats; int ret = 0; FILE *bout, *hout; #ifdef _PARALLEL_H int low; int high; #endif #ifdef _PARALLEL_H if (get_operation_mode() == SLAVE) { /* Send information to the master */ return send_generation_information ( gen, mpop, stt_interval, bestn ); } #endif /* number of decimal digits to use when printing fitness values. */ if ( fd == -1 ) fd = atoi ( get_parameter ( "output.digits" ) ); #ifdef PDEBUG_GP printf("Begin generation_info\n"); fflush(stdout); #endif /* allocate stats records for the current generation. */ gen_stats = (popstats *)MALLOC ( (mpop->size+1)*sizeof ( popstats ) ); for ( i = 0; i < mpop->size+1; ++i ) { gen_stats[i].bestn = bestn; gen_stats[i].size = -1; } oprintf ( OUT_GEN, 90, "=== GENERATION %d ===\n", gen ); oprintf ( OUT_PRG, 90, "=== GENERATION %d ===\n", gen ); /* for each subpopulation... */ #ifndef _PARALLEL_H for ( i = 0; i < mpop->size; ++i ) #else low = get_low(); high = get_high(); for ( i = low; i < high; ++i ) #endif { #ifdef PDEBUG_GP printf("gne_info = %d\n", i); fflush(stdout); #endif /* calculate stats for subpopulation. */ calculate_pop_stats ( gen_stats+i+1, mpop->pop[i], gen, i ); /* accumulate that into stats for whole popluation... */ accumulate_pop_stats ( gen_stats, gen_stats+i+1 ); /* ...and stats for this subpopulation over the whole run. */ accumulate_pop_stats ( run_stats+i+1, gen_stats+i+1 ); /* if only one subpop, don't print out the subpop stuff. */ if ( mpop->size == 1 ) continue; /** print much stuff to .gen, .prg, and .stt files. */ if ( test_detail_level ( 90 ) ) { oprintf ( OUT_GEN, 90, " subpopulation %d:\n", i+1 ); oprintf ( OUT_GEN, 90, " generation:\n" ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)gen_stats[i+1].totalnodes/gen_stats[i+1].size, gen_stats[i+1].minnodes, gen_stats[i+1].maxnodes, (double)gen_stats[i+1].totaldepth/gen_stats[i+1].size, gen_stats[i+1].mindepth, gen_stats[i+1].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", gen_stats[i+1].bestnodes, gen_stats[i+1].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", gen_stats[i+1].worstnodes, gen_stats[i+1].worstdepth ); oprintf ( OUT_GEN, 90, " run: (%d trees)\n", run_stats[i+1].size ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)run_stats[i+1].totalnodes/run_stats[i+1].size, run_stats[i+1].minnodes, run_stats[i+1].maxnodes, (double)run_stats[i+1].totaldepth/run_stats[i+1].size, run_stats[i+1].mindepth, run_stats[i+1].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", run_stats[i+1].bestnodes, run_stats[i+1].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", run_stats[i+1].worstnodes, run_stats[i+1].worstdepth ); } if ( test_detail_level ( 90 ) ) { oprintf ( OUT_PRG, 90, " subpopulation %d:\n", i+1 ); oprintf ( OUT_PRG, 90, " generation stats:\n" ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)gen_stats[i+1].totalhits/gen_stats[i+1].size, gen_stats[i+1].minhits, gen_stats[i+1].maxhits, fd, (double)gen_stats[i+1].totalfit/gen_stats[i+1].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf\n", gen_stats[i+1].besthits, fd, (double)gen_stats[i+1].bestfit ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf\n", gen_stats[i+1].worsthits, fd, (double)gen_stats[i+1].worstfit ); oprintf ( OUT_PRG, 90, " run stats: (%d trees)\n", run_stats[i+1].size ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)run_stats[i+1].totalhits/run_stats[i+1].size, run_stats[i+1].minhits, run_stats[i+1].maxhits, fd, (double)run_stats[i+1].totalfit/run_stats[i+1].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[i+1].besthits, fd, (double)run_stats[i+1].bestfit, run_stats[i+1].bestgen ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[i+1].worsthits, fd, (double)run_stats[i+1].worstfit, run_stats[i+1].worstgen ); } if ( gen%stt_interval == 0 ) { oprintf ( OUT_STT, 50, "%d %d ", gen, i+1 ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, gen_stats[i+1].totalfit/gen_stats[i+1].size, fd, gen_stats[i+1].bestfit, fd, gen_stats[i+1].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)gen_stats[i+1].totalnodes/gen_stats[i+1].size, (double)gen_stats[i+1].totaldepth/gen_stats[i+1].size, gen_stats[i+1].bestnodes, gen_stats[i+1].bestdepth, gen_stats[i+1].worstnodes, gen_stats[i+1].worstdepth ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, run_stats[i+1].totalfit/run_stats[i+1].size, fd, run_stats[i+1].bestfit, fd, run_stats[i+1].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)run_stats[i+1].totalnodes/run_stats[i+1].size, (double)run_stats[i+1].totaldepth/run_stats[i+1].size, run_stats[i+1].bestnodes, run_stats[i+1].bestdepth, run_stats[i+1].worstnodes, run_stats[i+1].worstdepth ); oprintf ( OUT_STT, 50, "\n" ); } } /* merge stats for current generation into overall run stats. */ newbest = accumulate_pop_stats ( run_stats, gen_stats ); /** more printing. **/ if ( test_detail_level ( 90 ) ) { oprintf ( OUT_GEN, 90, " total population:\n" ); oprintf ( OUT_GEN, 90, " generation:\n" ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)gen_stats[0].totalnodes/gen_stats[0].size, gen_stats[0].minnodes, gen_stats[0].maxnodes, (double)gen_stats[0].totaldepth/gen_stats[0].size, gen_stats[0].mindepth, gen_stats[0].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", gen_stats[0].bestnodes, gen_stats[0].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", gen_stats[0].worstnodes, gen_stats[0].worstdepth ); oprintf ( OUT_GEN, 90, " run: (%d trees)\n", run_stats[0].size ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)run_stats[0].totalnodes/run_stats[0].size, run_stats[0].minnodes, run_stats[0].maxnodes, (double)run_stats[0].totaldepth/run_stats[0].size, run_stats[0].mindepth, run_stats[0].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", run_stats[0].bestnodes, run_stats[0].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", run_stats[0].worstnodes, run_stats[0].worstdepth ); } if ( test_detail_level ( 90 ) ) { oprintf ( OUT_PRG, 90, " total population:\n" ); oprintf ( OUT_PRG, 90, " generation stats:\n" ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)gen_stats[0].totalhits/gen_stats[0].size, gen_stats[0].minhits, gen_stats[0].maxhits, fd, (double)gen_stats[0].totalfit/gen_stats[0].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf\n", gen_stats[0].besthits, fd, (double)gen_stats[0].bestfit ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf\n", gen_stats[0].worsthits, fd, (double)gen_stats[0].worstfit ); oprintf ( OUT_PRG, 90, " run stats: (%d trees)\n", run_stats[0].size ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)run_stats[0].totalhits/run_stats[0].size, run_stats[0].minhits, run_stats[0].maxhits, fd, (double)run_stats[0].totalfit/run_stats[0].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[0].besthits, fd, (double)run_stats[0].bestfit, run_stats[0].bestgen ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[0].worsthits, fd, (double)run_stats[0].worstfit, run_stats[0].worstgen ); } if ( gen%stt_interval == 0 ) { if ( test_detail_level ( 50 ) ) { oprintf ( OUT_STT, 50, "%d 0 ", gen ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, gen_stats[0].totalfit/gen_stats[0].size, fd, gen_stats[0].bestfit, fd, gen_stats[0].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)gen_stats[0].totalnodes/gen_stats[0].size, (double)gen_stats[0].totaldepth/gen_stats[0].size, gen_stats[0].bestnodes, gen_stats[0].bestdepth, gen_stats[0].worstnodes, gen_stats[0].worstdepth ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, run_stats[0].totalfit/run_stats[0].size, fd, run_stats[0].bestfit, fd, run_stats[0].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)run_stats[0].totalnodes/run_stats[0].size, (double)run_stats[0].totaldepth/run_stats[0].size, run_stats[0].bestnodes, run_stats[0].bestdepth, run_stats[0].worstnodes, run_stats[0].worstdepth ); oprintf ( OUT_STT, 50, "\n" ); } } /* rewrite the .bst file, and append to the .his file. */ if (get_operation_mode() != SLAVE) output_stream_open ( OUT_BST ); oprintf ( OUT_BST, 10, "=== BEST-OF-RUN ===\n" ); oprintf ( OUT_BST, 10, " generation: %d\n", run_stats[0].bestgen ); if ( mpop->size > 1 ) oprintf ( OUT_BST, 10, " subpopulation: %d\n", run_stats[0].bestpop+1 ); oprintf ( OUT_BST, 10, " nodes: %d\n", run_stats[0].bestnodes ); oprintf ( OUT_BST, 10, " depth: %d\n", run_stats[0].bestdepth ); oprintf ( OUT_BST, 10, " hits: %d\n", run_stats[0].besthits ); oprintf ( OUT_HIS, 10, "=== BEST-OF-RUN ===\n" ); oprintf ( OUT_HIS, 10, " current generation: %d\n", gen ); oprintf ( OUT_HIS, 10, " generation: %d\n", run_stats[0].bestgen ); if ( mpop->size > 1 ) oprintf ( OUT_HIS, 10, " subpopulation: %d\n", run_stats[0].bestpop+1 ); oprintf ( OUT_HIS, 10, " nodes: %d\n", run_stats[0].bestnodes ); oprintf ( OUT_HIS, 10, " depth: %d\n", run_stats[0].bestdepth ); oprintf ( OUT_HIS, 10, " hits: %d\n", run_stats[0].besthits ); /* retrieve the (FILE *) for the .bst and .his files, so that the trees can be printed to them. */ bout = output_filehandle ( OUT_BST ); hout = output_filehandle ( OUT_HIS ); if ( run_stats[0].bestn == 1 ) { oprintf ( OUT_BST, 20, "TOP INDIVIDUAL:\n\n" ); oprintf ( OUT_HIS, 20, "TOP INDIVIDUAL:\n\n" ); } else { oprintf ( OUT_BST, 20, "TOP %d INDIVIDUALS (in order):\n\n", run_stats[0].bestn ); oprintf ( OUT_HIS, 20, "TOP %d INDIVIDUALS (in order):\n\n", run_stats[0].bestn ); } for ( i = 0; i < run_stats[0].bestn; ++i ) { oprintf ( OUT_BST, 20, "\n\n-- #%d --\n", i+1 ); oprintf ( OUT_BST, 20, " hits: %d\n", run_stats[0].best[i]->ind->hits ); oprintf ( OUT_BST, 20, " raw fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->r_fitness ); oprintf ( OUT_BST, 20, " standardized fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->s_fitness ); oprintf ( OUT_BST, 20, " adjusted fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->a_fitness ); oprintf ( OUT_HIS, 20, "\n\n-- #%d --\n", i+1 ); oprintf ( OUT_HIS, 20, " hits: %d\n", run_stats[0].best[i]->ind->hits ); oprintf ( OUT_HIS, 20, " raw fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->r_fitness ); oprintf ( OUT_HIS, 20, " standardized fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->s_fitness ); oprintf ( OUT_HIS, 20, " adjusted fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->a_fitness ); /* print the tree to both files here. */ if ( test_detail_level ( 20 ) ) { pretty_print_individual ( run_stats[0].best[i]->ind, bout ); pretty_print_individual ( run_stats[0].best[i]->ind, hout ); } } /* call the end-of-evaluation callback. returns 1 if user termination criterion is met, 0 otherwise. */ ret = app_end_of_evaluation ( gen, mpop, newbest, gen_stats, run_stats ); /* close the .bst file. */ if (get_operation_mode() != SLAVE) output_stream_close ( OUT_BST ); /* free stats structures for current generation. */ #ifndef _PARALLEL_H for ( i = 0; i < mpop->size+1; ++i ) { for ( j = 0; j < gen_stats[i].bestn; ++j ) --gen_stats[i].best[j]->refcount; FREE ( gen_stats[i].best ); } #else low = get_low(); high = get_high(); /* We used only a part of the stats */ for ( i = low+1; i < high+1; ++i ) { for ( j = 0; j < gen_stats[i].bestn; ++j ) --gen_stats[i].best[j]->refcount; FREE ( gen_stats[i].best ); } /* Last but not least */ for ( j = 0; j < gen_stats[0].bestn; ++j ) --gen_stats[0].best[j]->refcount; FREE ( gen_stats[0].best ); #endif FREE ( gen_stats ); /* deallocate saved individuals that are no longer needed. */ saved_individual_gc(); #ifdef PDEBUG_GP printf("Finished generation_info()\n"); fflush(stdout); #endif /* return value the application callback gave us. */ return ret; } /* evaluate_pop() * * evaluates all the individuals in a population whose cached * fitness values are invalid. */ void evaluate_pop ( population *pop ) { int k; #ifdef DEBUG print_individual ( pop->ind, stdout ); app_eval_fitness ( pop->ind ); exit(0); #endif for ( k = 0; k < pop->size; ++k ) if ( pop->ind[k].evald != EVAL_CACHE_VALID ) app_eval_fitness ( (pop->ind)+k ); } /* calculate_pop_stats() * * tabulates stats for a population: fitness and size of best, worst, * mean, etc. also finds top N individuals and saves them. */ void calculate_pop_stats ( popstats *s, population *pop, int gen, int subpop ) { int i, j, k, l; int b; saved_ind *shp; individual **temp; /* allocate a list of the top N individuals. */ s->best = (saved_ind **)MALLOC ( s->bestn * sizeof ( saved_ind * ) ); temp = (individual **)MALLOC ( (s->bestn+1) * sizeof ( individual * ) ); s->size = pop->size; /** this is all pretty obvious -- set all the max and min values to the first individual's values, then go through the population looking for things that are bigger/smaller/better/worse/etc. **/ s->maxnodes = s->minnodes = s->totalnodes = s->bestnodes = s->worstnodes = individual_size ( pop->ind+0 ); s->maxdepth = s->mindepth = s->totaldepth = s->bestdepth = s->worstdepth = individual_depth ( pop->ind+0 ); s->maxhits = s->minhits = s->totalhits = s->besthits = s->worsthits = pop->ind[0].hits; s->bestfit = s->worstfit = s->totalfit = pop->ind[0].a_fitness; temp[0] = pop->ind; b = 1; s->bestgen = s->worstgen = gen; s->bestpop = s->worstpop = subpop; for ( i = 1; i < s->size; ++i ) { j = individual_size ( pop->ind+i ); s->totalnodes += j; if ( j < s->minnodes ) s->minnodes = j; if ( j > s->maxnodes ) s->maxnodes = j; k = individual_depth ( pop->ind+i ); s->totaldepth += k; if ( k < s->mindepth ) s->mindepth = k; if ( k > s->maxdepth ) s->maxdepth = k; l = pop->ind[i].hits; s->totalhits += l; if ( l < s->minhits ) s->minhits = l; if ( l > s->maxhits ) s->maxhits = l; s->totalfit += pop->ind[i].a_fitness; if ( pop->ind[i].a_fitness > s->bestfit ) { s->bestfit = pop->ind[i].a_fitness; s->bestnodes = j; s->bestdepth = k; s->besthits = l; } else if ( pop->ind[i].a_fitness < s->worstfit ) { s->worstfit = pop->ind[i].a_fitness; s->worstnodes = j; s->worstdepth = k; s->worsthits = l; } /** insert the current individual into the top N list (if it belongs there). **/ for ( j = b; j > 0; --j ) { if ( pop->ind[i].a_fitness < temp[j-1]->a_fitness ) break; temp[j] = temp[j-1]; } if ( j < s->bestn ) temp[j] = pop->ind+i; if ( b < s->bestn ) ++b; } /** now save copies of the individuals in the "temp" list **/ for ( i = 0; i < b; ++i ) { shp = (saved_ind *)MALLOC ( sizeof ( saved_ind ) ); shp->ind = (individual *)MALLOC ( sizeof ( individual ) ); shp->ind->tr = (tree *)MALLOC ( tree_count * sizeof ( tree ) ); duplicate_individual ( shp->ind, temp[i] ); for ( j = 0; j < tree_count; ++j ) reference_ephem_constants ( shp->ind->tr[j].data, 1 ); shp->refcount = 1; shp->next = NULL; saved_tail->next = shp; saved_tail = shp; ++saved_head->refcount; s->best[i] = shp; } #ifdef _PARALLEL_H s->real_size = b; #endif #ifdef DEBUG printf ( "the best list is:\n" ); for ( j = 0; j < s->bestn; ++j ) printf ( " %08x %lf\n", s->best[j], s->best[j]->ind->a_fitness ); #endif FREE ( temp ); } /* accumulate_pop_stats() * * this merges the second statistics record into the first, so that it reflects * the "sum" of the underlying populations. returns 1 if the best individual * of the first record has changed (that is, if the second record has a better * best individual. */ int accumulate_pop_stats ( popstats *total, popstats *n ) { int ret = 0; int i, j, k; saved_ind **temp; if ( total->size == -1 ) { /* if the "total" record is empty, then just copy the second record into it. */ memcpy ( total, n, sizeof ( popstats ) ); total->best = (saved_ind **)MALLOC ( total->bestn * sizeof ( saved_ind * ) ); memcpy ( total->best, n->best, total->bestn * sizeof ( saved_ind * ) ); ret = 1; } else { /* sum the totals. */ total->size += n->size; total->totalnodes += n->totalnodes; total->totaldepth += n->totaldepth; total->totalhits += n->totalhits; total->totalfit += n->totalfit; /* find the maximums. */ if ( n->maxnodes > total->maxnodes ) total->maxnodes = n->maxnodes; if ( n->maxdepth > total->maxdepth ) total->maxdepth = n->maxdepth; if ( n->maxhits > total->maxhits ) total->maxhits = n->maxhits; /* find the minimums. */ if ( n->minnodes < total->minnodes ) total->minnodes = n->minnodes; if ( n->mindepth < total->mindepth ) total->mindepth = n->mindepth; if ( n->minhits < total->minhits ) total->minhits = n->minhits; /* find the best individual's numbers. */ if ( n->bestfit > total->bestfit ) { total->bestfit = n->bestfit; total->bestnodes = n->bestnodes; total->bestdepth = n->bestdepth; total->besthits = n->besthits; total->bestgen = n->bestgen; total->bestpop = n->bestpop; ret = 1; } /* find the worst individual's numbers. */ if ( n->worstfit < total->worstfit ) { total->worstfit = n->worstfit; total->worstnodes = n->worstnodes; total->worstdepth = n->worstdepth; total->worsthits = n->worsthits; total->worstgen = n->worstgen; total->worstpop = n->worstpop; } #ifdef DEBUG printf ( "total list:\n" ); for ( i = 0; i < total->bestn; ++i ) printf ( " %08x %lf\n", total->best[i], total->best[i]->ind->a_fitness ); printf ( "new list:\n" ); for ( i = 0; i < n->bestn; ++i ) printf ( " %08x %lf\n", n->best[i], n->best[i]->ind->a_fitness ); #endif /** here we merge the two "top N" lists into one, discarding the remaining N individuals. **/ temp = (saved_ind **)MALLOC ( total->bestn * sizeof ( saved_ind * ) ); j = 0; /* position in "total"s list */ k = 0; /* position in "n"s list */ for ( i = 0; i < total->bestn; ++i ) { /* if the n list is empty, take from the total list. */ if ( k == -1 ) temp[i] = total->best[j++]; /* if the total list is empty, take from the n list. */ else if ( j == -1 ) { ret |= (i==0); temp[i] = n->best[k++]; } /* if neither list is empty, take the better individual. */ else if ( total->best[j]->ind->a_fitness < n->best[k]->ind->a_fitness ) { ret |= (i==0); temp[i] = n->best[k++]; } else temp[i] = total->best[j++]; /* have we run off the end of either list? */ if ( j >= total->bestn ) j = -1; if ( k >= n->bestn ) k = -1; } /* decrement the reference count of the old "best" list. */ for ( i = 0; i < total->bestn; ++i ) --total->best[i]->refcount; FREE ( total->best ); total->best = temp; #ifdef DEBUG printf ( "new total list:\n" ); for ( i = 0; i < total->bestn; ++i ) printf ( " %08x %lf\n", total->best[i], total->best[i]->ind->a_fitness ); #endif } /* increment the reference count of the new "best" list. */ for ( i = 0; i < total->bestn; ++i ) ++total->best[i]->refcount; return ret; } /* saved_individual_gc() * * go through the list of saved individuals, deleting any which are no longer * referred to. */ void saved_individual_gc ( void ) { int j; saved_ind *shp = saved_head->next; saved_ind *shm = saved_head; //printf("refcount head = %d\n", shm->refcount); while ( shp ) { //printf("refcount = %d\n", shp->refcount); if ( shp->refcount == 0 ) { /** found one that needs to be deleted. **/ /* dereference its trees' ERCs and delete the trees. */ for ( j = 0; j < tree_count; ++j ) { reference_ephem_constants ( shp->ind->tr[j].data, -1 ); free_tree ( shp->ind->tr+j ); } FREE ( shp->ind->tr ); FREE ( shp->ind ); /* cut the record out of the linked list. */ shm->next = shp->next; if ( saved_tail == shp ) saved_tail = shm; FREE ( shp ); /* bug fix, janjf@cnr.colostate.edu */ shp = shm->next; /* the refcount field of the list head (a dummy node) holds the size of the list. */ --saved_head->refcount; } else { /* move down the list. */ shm = shp; shp = shp->next; } } } /* read_saved_individuals() * * reads the list of saved individuals from a checkpoint file. constructs * an index translating indices to addresses. */ saved_ind ** read_saved_individuals ( ephem_const **eind, FILE *f ) { char *buffer; int count; int i; saved_ind *p; saved_ind **sind; buffer = (char *)MALLOC ( MAXCHECKLINELENGTH ); /* read the number of saved individuals. */ fscanf ( f, "%*s %d\n", &count ); /* allocate the index. */ sind = (saved_ind **)MALLOC ( count * sizeof ( saved_ind * ) ); /* allocate the head of the linked list (a dummy node whose refcount equals the number of individuals on the list). */ saved_head = (saved_ind *)MALLOC ( sizeof ( saved_ind ) ); saved_head->ind = NULL; saved_head->refcount = count; p = saved_head; for ( i = 0; i < count; ++i ) { /* allocate the next saved_ind on the list. */ p->next = (saved_ind *)MALLOC ( sizeof ( saved_ind ) ); p = p->next; /* allocate the individual. */ p->ind = (individual *)MALLOC ( sizeof ( individual ) ); /* make the index entry. */ sind[i] = p; /* read the refcount. */ fscanf ( f, "%d ", &(p->refcount) ); /* read the individual. */ read_individual ( p->ind, eind, f, buffer ); } /* mark the end of the list. */ p->next = NULL; saved_tail = p; FREE ( buffer ); return sind; } /* read_stats_checkpoint() * * read the overall run statistics structures from a checkpoint file. */ void read_stats_checkpoint ( multipop *mpop, ephem_const **eind, FILE *f ) { int i, j, k; saved_ind **sind; /* read and index the saved individuals list. */ sind = read_saved_individuals ( eind, f ); /* allocate the run_stats array. */ run_stats = (popstats *)MALLOC ( (mpop->size+1)*sizeof ( popstats ) ); for ( i = 0; i < mpop->size+1; ++i ) { /* read lots of integer values into run_stats. */ fscanf ( f, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", &(run_stats[i].size), &(run_stats[i].maxnodes), &(run_stats[i].minnodes), &(run_stats[i].totalnodes), &(run_stats[i].bestnodes), &(run_stats[i].worstnodes), &(run_stats[i].maxdepth), &(run_stats[i].mindepth), &(run_stats[i].totaldepth), &(run_stats[i].bestdepth), &(run_stats[i].worstdepth), &(run_stats[i].maxhits), &(run_stats[i].minhits), &(run_stats[i].totalhits), &(run_stats[i].besthits), &(run_stats[i].worsthits) ); /** double-precision values are stored as hex data to avoid loss of precision. **/ read_hex_block ( &(run_stats[i].bestfit), sizeof ( double ), f ); fgetc ( f ); read_hex_block ( &(run_stats[i].worstfit), sizeof ( double ), f ); fgetc ( f ); read_hex_block ( &(run_stats[i].totalfit), sizeof ( double ), f ); /* they are also printed as decimal values, for the benefit of human readers -- skip these fields. */ fscanf ( f, " %*f %*f %*f\n" ); /* read some more integers. */ fscanf ( f, "%d %d %d %d %d ", &(run_stats[i].bestgen), &(run_stats[i].worstgen), &(run_stats[i].bestpop), &(run_stats[i].worstpop), &(run_stats[i].bestn) ); run_stats[i].best = (saved_ind **)MALLOC ( run_stats[i].bestn * sizeof ( saved_ind * ) ); /** read the indices of the contents of the best array, and look up the addresses in the index. **/ for ( j = 0; j < run_stats[i].bestn; ++j ) { fscanf ( f, "%d\n", &k ); run_stats[i].best[j] = sind[k]; } } FREE ( sind ); } /* write_saved_individuals() * * writes the linked list of saved individuals to a checkpoint file. returns * an index for translating saved_ind addresses to integer indices. */ saved_ind ** write_saved_individuals ( ephem_index *eind, FILE *f ) { saved_ind **index; saved_ind *shp; int i = 0; index = (saved_ind **)MALLOC ( saved_head->refcount * sizeof ( saved_ind * ) ); /* write the count of individuals. */ fprintf ( f, "saved-individual-count: %d\n", saved_head->refcount ); shp = saved_head->next; /** traverse the linked list. **/ while ( shp ) { /* write the reference count and individual. */ fprintf ( f, "%d ", shp->refcount ); write_individual ( shp->ind, eind, f ); /* record the address in the index. */ index[i++] = shp; shp = shp->next; } return index; } /* write_stats_checkpoint() * * write the overall run statistics structures to a checkpoint file. */ void write_stats_checkpoint ( multipop *mpop, ephem_index *eind, FILE *f ) { int i, j, k; saved_ind **sind; /* write and index the saved individuals list. */ sind = write_saved_individuals ( eind, f ); for ( i = 0; i < mpop->size+1; ++i ) { /* write many integer values. */ fprintf ( f, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", run_stats[i].size, run_stats[i].maxnodes, run_stats[i].minnodes, run_stats[i].totalnodes, run_stats[i].bestnodes, run_stats[i].worstnodes, run_stats[i].maxdepth, run_stats[i].mindepth, run_stats[i].totaldepth, run_stats[i].bestdepth, run_stats[i].worstdepth, run_stats[i].maxhits, run_stats[i].minhits, run_stats[i].totalhits, run_stats[i].besthits, run_stats[i].worsthits ); /** write double-precision values as hex data. **/ write_hex_block ( &(run_stats[i].bestfit), sizeof ( double ), f ); fputc ( ' ', f ); write_hex_block ( &(run_stats[i].worstfit), sizeof ( double ), f ); fputc ( ' ', f ); write_hex_block ( &(run_stats[i].totalfit), sizeof ( double ), f ); /* also write them as decimal values. */ fprintf ( f, " %f %f %f\n", run_stats[i].bestfit, run_stats[i].worstfit, run_stats[i].totalfit ); /* write more integers. */ fprintf ( f, "%d %d %d %d %d ", run_stats[i].bestgen, run_stats[i].worstgen, run_stats[i].bestpop, run_stats[i].worstpop, run_stats[i].bestn ); /** write the best array, indexing saved individuals using integers. **/ for ( j = 0; j < run_stats[i].bestn; ++j ) { /** search the index for the address. **/ for ( k = 0; k < saved_head->refcount; ++k ) if ( run_stats[i].best[j] == sind[k] ) { /* print the index to the checkpoint file. */ fprintf ( f, " %d", k ); break; } /** address was not found in the index. **/ if ( k == saved_head->refcount ) { /* this shouldn't ever happen. */ fprintf ( f, " -1" ); error ( E_WARNING, "bestn pointer is bad." ); } } fputc ( '\n', f ); } FREE ( sind ); } #ifdef _PARALLEL_H /* set_term() * * set "term" variable. */ void set_term ( int t ) { term = t; return; } /* get_term() * * get "term" value. */ int get_term ( void ) { return term; } /* send_generation_information() * * calculates and prints population statistics send by the different nodes. */ int send_generation_information ( int gen, multipop *mpop, int stt_interval, int bestn ) { int i, j; int newbest; static int fd = -1; popstats *gen_stats; int ret = 0; #ifdef _PARALLEL_H int low; int high; #endif /* number of decimal digits to use when printing fitness values. */ if ( fd == -1 ) fd = atoi ( get_parameter ( "output.digits" ) ); #ifdef PDEBUG_GP printf("Begin generation_info\n"); fflush(stdout); #endif /* allocate stats records for the current generation. */ gen_stats = (popstats *)MALLOC ( (mpop->size+1)*sizeof ( popstats ) ); for ( i = 0; i < mpop->size+1; ++i ) { gen_stats[i].bestn = bestn; gen_stats[i].size = -1; } oprintf ( OUT_GEN, 90, "=== GENERATION %d ===\n", gen ); oprintf ( OUT_PRG, 90, "=== GENERATION %d ===\n", gen ); /* for each subpopulation... */ low = get_low(); high = get_high(); for ( i = low; i < high; ++i ) { #ifdef PDEBUG_GP printf("gne_info = %d\n", i); fflush(stdout); #endif /* calculate stats for subpopulation. */ calculate_pop_stats ( gen_stats+i+1, mpop->pop[i], gen, i ); /* send stats for the i-th subpopulation. */ send_pop_stats ( gen_stats+i+1, gen, i ); /* accumulate that into stats for whole popluation... */ accumulate_pop_stats ( gen_stats, gen_stats+i+1 ); /* ...and stats for this subpopulation over the whole run. */ accumulate_pop_stats ( run_stats+i+1, gen_stats+i+1 ); /* if only one subpop, don't print out the subpop stuff. */ if ( mpop->size == 1 ) continue; } /* merge stats for current generation into overall run stats. */ newbest = accumulate_pop_stats ( run_stats, gen_stats ); /* call the end-of-evaluation callback. returns 1 if user termination criterion is met, 0 otherwise. */ ret = app_end_of_evaluation ( gen, mpop, newbest, gen_stats, run_stats ); /* free stats structures for current generation. */ low = get_low(); high = get_high(); /* We used only a part of the stats */ for ( i = low+1; i < high+1; ++i ) { for ( j = 0; j < gen_stats[i].bestn; ++j ) --gen_stats[i].best[j]->refcount; FREE ( gen_stats[i].best ); } /* Last but not least */ for ( j = 0; j < gen_stats[0].bestn; ++j ) --gen_stats[0].best[j]->refcount; FREE ( gen_stats[0].best ); FREE ( gen_stats ); /* deallocate saved individuals that are no longer needed. */ saved_individual_gc(); #ifdef PDEBUG_GP printf("Finished generation_info()\n"); fflush(stdout); #endif /* return value the application callback gave us. */ return ret; } /* pack_saved_ind() * * packs a saved individual. */ void pack_saved_ind (saved_ind *ptr) { pack_individual(ptr->ind); if (pvm_pkint (&(ptr->refcount), 1, 1)) pvm_perror("pack_saved_ind error packing \"refcount\""); return; } /* unpack_saved_ind() * * unpacks a saved individual. */ void unpack_saved_ind (saved_ind **ptr) { saved_ind *ret; ret = (saved_ind *)MALLOC ( sizeof ( saved_ind )); unpack_individual(&(ret->ind)); if (pvm_upkint (&(ret->refcount), 1, 1)) pvm_perror("unpack_saved_ind error unpacking \"refcount\""); *ptr = ret; return; } /* send_pop_stats() * * send the statistics to the master node. */ void send_pop_stats ( popstats *s, int gen, int subpop ) { int i; int parent_tid; parent_tid = pvm_parent(); if (parent_tid == PvmNoParent) { error( E_FATAL_ERROR, "No parent for process in send_pop_stats()"); } pvm_initsend(ENCODING); if (pvm_pkint(&gen, 1, 1)) pvm_perror("send_pop_stats error packing \"gen\""); if (pvm_pkint(&subpop, 1, 1)) pvm_perror("send_pop_stats error packing \"subpop\""); if (pvm_pkint(&s->real_size, 1, 1)) pvm_perror("send_pop_stats error packing \"real_size\""); /* Pack the original information elements */ if (pvm_pkint(&s->size, 1, 1)) pvm_perror("send_pop_stats error packing \"size\""); if (pvm_pkint(&s->maxnodes, 1, 1)) pvm_perror("send_pop_stats error packing \"maxnodes\""); if (pvm_pkint(&s->minnodes, 1, 1)) pvm_perror("send_pop_stats error packing \"minnodes\""); if (pvm_pkint(&s->totalnodes, 1, 1)) pvm_perror("send_pop_stats error packing \"totalnodes\""); if (pvm_pkint(&s->bestnodes, 1, 1)) pvm_perror("send_pop_stats error packing \"bestnodes\""); if (pvm_pkint(&s->worstnodes, 1, 1)) pvm_perror("send_pop_stats error packing \"worstnodes\""); if (pvm_pkint(&s->maxdepth, 1, 1)) pvm_perror("send_pop_stats error packing \"maxdepth\""); if (pvm_pkint(&s->mindepth, 1, 1)) pvm_perror("send_pop_stats error packing \"mindepth\""); if (pvm_pkint(&s->totaldepth, 1, 1)) pvm_perror("send_pop_stats error packing \"totaldepth\""); if (pvm_pkint(&s->bestdepth, 1, 1)) pvm_perror("send_pop_stats error packing \"bestdepth\""); if (pvm_pkint(&s->worstdepth, 1, 1)) pvm_perror("send_pop_stats error packing \"worstdepth\""); if (pvm_pkint(&s->maxhits, 1, 1)) pvm_perror("send_pop_stats error packing \"maxhits\""); if (pvm_pkint(&s->minhits, 1, 1)) pvm_perror("send_pop_stats error packing \"minhits\""); if (pvm_pkint(&s->totalhits, 1, 1)) pvm_perror("send_pop_stats error packing \"totalhits\""); if (pvm_pkint(&s->besthits, 1, 1)) pvm_perror("send_pop_stats error packing \"besthits\""); if (pvm_pkint(&s->worsthits, 1, 1)) pvm_perror("send_pop_stats error packing \"worsthits\""); if (pvm_pkdouble(&s->bestfit, 1, 1)) pvm_perror("send_pop_stats error packing \"bestfit\""); if (pvm_pkdouble(&s->worstfit, 1, 1)) pvm_perror("send_pop_stats error packing \"worstfit\""); if (pvm_pkdouble(&s->totalfit, 1, 1)) pvm_perror("send_pop_stats error packing \"totalfit\""); if (pvm_pkint(&s->bestgen, 1, 1)) pvm_perror("send_pop_stats error packing \"bestgen\""); if (pvm_pkint(&s->worstgen, 1, 1)) pvm_perror("send_pop_stats error packing \"worstgen\""); if (pvm_pkint(&s->bestpop, 1, 1)) pvm_perror("send_pop_stats error packing \"bestpop\""); if (pvm_pkint(&s->worstpop, 1, 1)) pvm_perror("send_pop_stats error packing \"worstpop\""); if (pvm_pkint(&s->bestn, 1, 1)) pvm_perror("send_pop_stats error packing \"bestn\""); /* Pack the different individuals */ for (i=0; ireal_size; i++) pack_saved_ind (s->best[i]); /* Pack some timing information */ pack_event(get_tree_send_event()); pack_event(get_tree_receive_event()); pack_event(get_individual_send_event()); pack_event(get_individual_receive_event()); // use global vsriable :-( should be removed later... pack_event(&eval_diff); pack_event(&breed_diff); /* Send it */ pvm_send(parent_tid, STATS_TAG); /* printf ("Trees RX %s TX %s -- ", event_string(get_tree_receive_event()) , event_string(get_tree_send_event())); printf ("Individuals RX %s TX %s\n", event_string(get_individual_receive_event()) , event_string(get_individual_send_event())); */ return; } /* receive_pop_stats() * * receives the statistics from one the slave nodes, allocates the necessary memory. */ void receive_pop_stats ( popstats *s, int *gen, int *subpop ) { int i, j; saved_ind *shp; /* Unpack the information needed place the statistics in the correct context. */ if (pvm_upkint(gen, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"gen\""); if (pvm_upkint(subpop, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"subpop\""); /* !! We shift the pointer to the statistics HERE !! */ s += *subpop + 1; if (pvm_upkint(&s->real_size, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"real_size\""); /* Unpack the original information elements */ if (pvm_upkint(&s->size, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"size\""); if (pvm_upkint(&s->maxnodes, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"maxnodes\""); if (pvm_upkint(&s->minnodes, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"minnodes\""); if (pvm_upkint(&s->totalnodes, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"totalnodes\""); if (pvm_upkint(&s->bestnodes, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"bestnodes\""); if (pvm_upkint(&s->worstnodes, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"worstnodes\""); if (pvm_upkint(&s->maxdepth, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"maxdepth\""); if (pvm_upkint(&s->mindepth, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"mindepth\""); if (pvm_upkint(&s->totaldepth, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"totaldepth\""); if (pvm_upkint(&s->bestdepth, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"bestdepth\""); if (pvm_upkint(&s->worstdepth, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"worstdepth\""); if (pvm_upkint(&s->maxhits, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"maxhits\""); if (pvm_upkint(&s->minhits, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"minhits\""); if (pvm_upkint(&s->totalhits, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"totalhits\""); if (pvm_upkint(&s->besthits, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"besthits\""); if (pvm_upkint(&s->worsthits, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"worsthits\""); if (pvm_upkdouble(&s->bestfit, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"bestfit\""); if (pvm_upkdouble(&s->worstfit, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"worstfit\""); if (pvm_upkdouble(&s->totalfit, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"totalfit\""); if (pvm_upkint(&s->bestgen, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"bestgen\""); if (pvm_upkint(&s->worstgen, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"worstgen\""); if (pvm_upkint(&s->bestpop, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"bestpop\""); if (pvm_upkint(&s->worstpop, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"worstpop\""); if (pvm_upkint(&s->bestn, 1, 1)) pvm_perror("receive_pop_stats error unpacking \"bestn\""); /* allocate a list of the top N individuals. */ s->best = (saved_ind **)MALLOC ( s->bestn * sizeof ( saved_ind * ) ); /* We unpack the individuals, these are already the best ones */ for (i=0; ireal_size; i++) unpack_saved_ind (s->best+i); /* The individuals should be put in the linked list of saved individual */ /** now save copies of the individuals in the "temp" list **/ for ( i = 0; i < s->real_size; ++i ) { shp = s->best[i]; for ( j = 0; j < tree_count; ++j ) reference_ephem_constants ( shp->ind->tr[j].data, 1 ); shp->refcount = 1; shp->next = NULL; saved_tail->next = shp; saved_tail = shp; ++saved_head->refcount; } /* Unpack thtiming information */ unpack_event(get_tree_send_event()); unpack_event(get_tree_receive_event()); unpack_event(get_individual_send_event()); unpack_event(get_individual_receive_event()); unpack_event(&eval); unpack_event(&breeding); return; } /* receive_generation_information() * * receives and prints population statistics send by the different nodes. */ Popstats_list *receive_generation_information( multipop *mpop, int *gen, Popstats_list **stats_list ) { int i; int newbest; static int fd = -1; int ret = 0; int bestn = 0; int stt_interval = 0; int subpop; char keep_gen_stats = 0; popstats *gen_stats = NULL; Popstats_list *stats; FILE *bout, *hout; /* number of decimal digits to use when printing fitness values. */ if ( fd == -1 ) fd = atoi ( get_parameter ( "output.digits" ) ); bestn = atoi ( get_parameter ( "output.bestn" ) ); if ( bestn < 1 ) { error ( E_WARNING, "\"output.bestn\" must be at least 1. defaulting to 1." ); bestn = 1; } /* get the interval for writing information to the .stt file. */ stt_interval = atoi ( get_parameter ( "output.stt_interval" ) ); if ( stt_interval < 1 ) error ( E_FATAL_ERROR, "\"output.stt_interval\" must be greater than zero." ); #ifdef PDEBUG_GP printf("Begin receive_generation_info\n"); fflush(stdout); #endif /* During the first call we need to allocate the memory for the run statistics. */ if (run_stats == NULL) { /* allocate statistics for overall run. */ run_stats = (popstats *)MALLOC ( (mpop->size+1)*sizeof ( popstats ) ); for ( i = 0; i < mpop->size+1; ++i ) { run_stats[i].bestn = bestn; run_stats[i].best = NULL; run_stats[i].size = -1; } } /* During the first call we need to allocate the memory for the first element of the list. */ if (saved_head == NULL) { /* initialize the linked list of saved individuals. */ saved_head = (saved_ind *)MALLOC ( sizeof ( saved_ind ) ); saved_head->ind = NULL; saved_head->refcount = 0; saved_head->next = NULL; saved_tail = saved_head; } /* allocate stats records to receive the statistics. */ gen_stats = (popstats *)MALLOC ( (mpop->size+1)*sizeof ( popstats ) ); for ( i = 0; i < mpop->size+1; ++i ) { gen_stats[i].bestn = bestn; gen_stats[i].best = NULL; gen_stats[i].size = -1; } /* receive stats for exactly "1" subpopulation. The statistics are immediatly stored in the correct place in the array. (gen_stats) */ receive_pop_stats ( gen_stats, gen, &subpop ); /* I am sooo lazy ... */ i = subpop; /* Look of statistics in the list */ stats = find_popstats ( stats_list, *gen); #ifdef PDEBUG_GP printf ("stats->gen = %d , stats->count = %d , gen = %d\n", stats->gen, stats->count, *gen); #endif /* Did we already have this one in stock? ;) */ if (stats->count == 0 ) { /* No, so we take use the currently allocated popstats (gen_stats) We should also make sure that we do not deallocate the memory now! */ stats->stats = gen_stats; stats->gen = *gen; keep_gen_stats = 1; } else { /* We already had some statistics about this population */ /* we copy the new stats in it. */ stats->stats[i+1] = gen_stats[i+1]; /* We deallocate the statistics : without dereferencing the individuals! */ FREE(gen_stats); /* We substitute the statistics we already have to gen_stats */ gen_stats = stats->stats; } stats->count++; stats->eval[i] = eval; stats->breeding[i] = breeding; oprintf ( OUT_GEN, 90, "=== GENERATION %d ===\n", *gen ); oprintf ( OUT_PRG, 90, "=== GENERATION %d ===\n", *gen ); /* for each subpopulation... */ { #ifdef PDEBUG_GP printf("receive_generation_info subpop = %d\n", i); fflush(stdout); #endif /* accumulate that into stats for whole popluation... */ accumulate_pop_stats ( gen_stats, gen_stats + i + 1 ); /* ...and stats for this subpopulation over the whole run. */ accumulate_pop_stats ( run_stats+i+1, gen_stats+i+1 ); /* if only one subpop, don't print out the subpop stuff. */ /* if ( mpop->size == 1 ) break; */ /** print much stuff to .gen, .prg, and .stt files. */ if ( test_detail_level ( 90 ) ) { oprintf ( OUT_GEN, 90, " subpopulation %d:\n", i+1 ); oprintf ( OUT_GEN, 90, " generation:\n" ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)gen_stats[i+1].totalnodes/gen_stats[i+1].size, gen_stats[i+1].minnodes, gen_stats[i+1].maxnodes, (double)gen_stats[i+1].totaldepth/gen_stats[i+1].size, gen_stats[i+1].mindepth, gen_stats[i+1].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", gen_stats[i+1].bestnodes, gen_stats[i+1].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", gen_stats[i+1].worstnodes, gen_stats[i+1].worstdepth ); oprintf ( OUT_GEN, 90, " run: (%d trees)\n", run_stats[i+1].size ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)run_stats[i+1].totalnodes/run_stats[i+1].size, run_stats[i+1].minnodes, run_stats[i+1].maxnodes, (double)run_stats[i+1].totaldepth/run_stats[i+1].size, run_stats[i+1].mindepth, run_stats[i+1].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", run_stats[i+1].bestnodes, run_stats[i+1].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", run_stats[i+1].worstnodes, run_stats[i+1].worstdepth ); } if ( test_detail_level ( 90 ) ) { oprintf ( OUT_PRG, 90, " subpopulation %d:\n", i+1 ); oprintf ( OUT_PRG, 90, " generation stats:\n" ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)gen_stats[i+1].totalhits/gen_stats[i+1].size, gen_stats[i+1].minhits, gen_stats[i+1].maxhits, fd, (double)gen_stats[i+1].totalfit/gen_stats[i+1].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf\n", gen_stats[i+1].besthits, fd, (double)gen_stats[i+1].bestfit ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf\n", gen_stats[i+1].worsthits, fd, (double)gen_stats[i+1].worstfit ); oprintf ( OUT_PRG, 90, " run stats: (%d trees)\n", run_stats[i+1].size ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)run_stats[i+1].totalhits/run_stats[i+1].size, run_stats[i+1].minhits, run_stats[i+1].maxhits, fd, (double)run_stats[i+1].totalfit/run_stats[i+1].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[i+1].besthits, fd, (double)run_stats[i+1].bestfit, run_stats[i+1].bestgen ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[i+1].worsthits, fd, (double)run_stats[i+1].worstfit, run_stats[i+1].worstgen ); } if ( *gen%stt_interval == 0 ) { oprintf ( OUT_STT, 50, "%d %d ", *gen, i+1 ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, gen_stats[i+1].totalfit/gen_stats[i+1].size, fd, gen_stats[i+1].bestfit, fd, gen_stats[i+1].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)gen_stats[i+1].totalnodes/gen_stats[i+1].size, (double)gen_stats[i+1].totaldepth/gen_stats[i+1].size, gen_stats[i+1].bestnodes, gen_stats[i+1].bestdepth, gen_stats[i+1].worstnodes, gen_stats[i+1].worstdepth ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, run_stats[i+1].totalfit/run_stats[i+1].size, fd, run_stats[i+1].bestfit, fd, run_stats[i+1].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)run_stats[i+1].totalnodes/run_stats[i+1].size, (double)run_stats[i+1].totaldepth/run_stats[i+1].size, run_stats[i+1].bestnodes, run_stats[i+1].bestdepth, run_stats[i+1].worstnodes, run_stats[i+1].worstdepth ); oprintf ( OUT_STT, 50, "\n" ); } } if (stats->count == mpop->size) { /* merge stats for current generation into overall run stats. */ newbest = accumulate_pop_stats ( run_stats, gen_stats ); /** more printing. **/ if ( test_detail_level ( 90 ) ) { oprintf ( OUT_GEN, 90, " total population:\n" ); oprintf ( OUT_GEN, 90, " generation:\n" ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)gen_stats[0].totalnodes/gen_stats[0].size, gen_stats[0].minnodes, gen_stats[0].maxnodes, (double)gen_stats[0].totaldepth/gen_stats[0].size, gen_stats[0].mindepth, gen_stats[0].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", gen_stats[0].bestnodes, gen_stats[0].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", gen_stats[0].worstnodes, gen_stats[0].worstdepth ); oprintf ( OUT_GEN, 90, " run: (%d trees)\n", run_stats[0].size ); oprintf ( OUT_GEN, 90, " mean: nodes: %.3lf (%d-%d); depth: %.3lf (%d-%d)\n", (double)run_stats[0].totalnodes/run_stats[0].size, run_stats[0].minnodes, run_stats[0].maxnodes, (double)run_stats[0].totaldepth/run_stats[0].size, run_stats[0].mindepth, run_stats[0].maxdepth ); oprintf ( OUT_GEN, 90, " best: nodes: %d; depth: %d\n", run_stats[0].bestnodes, run_stats[0].bestdepth ); oprintf ( OUT_GEN, 90, " worst: nodes: %d; depth: %d\n", run_stats[0].worstnodes, run_stats[0].worstdepth ); } if ( test_detail_level ( 90 ) ) { oprintf ( OUT_PRG, 90, " total population:\n" ); oprintf ( OUT_PRG, 90, " generation stats:\n" ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)gen_stats[0].totalhits/gen_stats[0].size, gen_stats[0].minhits, gen_stats[0].maxhits, fd, (double)gen_stats[0].totalfit/gen_stats[0].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf\n", gen_stats[0].besthits, fd, (double)gen_stats[0].bestfit ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf\n", gen_stats[0].worsthits, fd, (double)gen_stats[0].worstfit ); oprintf ( OUT_PRG, 90, " run stats: (%d trees)\n", run_stats[0].size ); oprintf ( OUT_PRG, 90, " mean: hits: %.3lf (%d-%d); standardized fitness: %.*lf\n", (double)run_stats[0].totalhits/run_stats[0].size, run_stats[0].minhits, run_stats[0].maxhits, fd, (double)run_stats[0].totalfit/run_stats[0].size ); oprintf ( OUT_PRG, 90, " best: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[0].besthits, fd, (double)run_stats[0].bestfit, run_stats[0].bestgen ); oprintf ( OUT_PRG, 90, " worst: hits: %d; standardized fitness: %.*lf; generation: %d\n", run_stats[0].worsthits, fd, (double)run_stats[0].worstfit, run_stats[0].worstgen ); } if ( *gen%stt_interval == 0 ) { if ( test_detail_level ( 50 ) ) { oprintf ( OUT_STT, 50, "%d 0 ", *gen ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, gen_stats[0].totalfit/gen_stats[0].size, fd, gen_stats[0].bestfit, fd, gen_stats[0].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)gen_stats[0].totalnodes/gen_stats[0].size, (double)gen_stats[0].totaldepth/gen_stats[0].size, gen_stats[0].bestnodes, gen_stats[0].bestdepth, gen_stats[0].worstnodes, gen_stats[0].worstdepth ); oprintf ( OUT_STT, 50, "%.*lf %.*lf %.*lf ", fd, run_stats[0].totalfit/run_stats[0].size, fd, run_stats[0].bestfit, fd, run_stats[0].worstfit ); oprintf ( OUT_STT, 50, "%.3lf %.3lf %d %d %d %d ", (double)run_stats[0].totalnodes/run_stats[0].size, (double)run_stats[0].totaldepth/run_stats[0].size, run_stats[0].bestnodes, run_stats[0].bestdepth, run_stats[0].worstnodes, run_stats[0].worstdepth ); oprintf ( OUT_STT, 50, "\n" ); } } /* rewrite the .bst file, and append to the .his file. */ output_stream_open ( OUT_BST ); oprintf ( OUT_BST, 10, "=== BEST-OF-RUN ===\n" ); oprintf ( OUT_BST, 10, " generation: %d\n", run_stats[0].bestgen ); if ( mpop->size > 1 ) oprintf ( OUT_BST, 10, " subpopulation: %d\n", run_stats[0].bestpop+1 ); oprintf ( OUT_BST, 10, " nodes: %d\n", run_stats[0].bestnodes ); oprintf ( OUT_BST, 10, " depth: %d\n", run_stats[0].bestdepth ); oprintf ( OUT_BST, 10, " hits: %d\n", run_stats[0].besthits ); oprintf ( OUT_HIS, 10, "=== BEST-OF-RUN ===\n" ); oprintf ( OUT_HIS, 10, " current generation: %d\n", *gen ); oprintf ( OUT_HIS, 10, " generation: %d\n", run_stats[0].bestgen ); if ( mpop->size > 1 ) oprintf ( OUT_HIS, 10, " subpopulation: %d\n", run_stats[0].bestpop+1 ); oprintf ( OUT_HIS, 10, " nodes: %d\n", run_stats[0].bestnodes ); oprintf ( OUT_HIS, 10, " depth: %d\n", run_stats[0].bestdepth ); oprintf ( OUT_HIS, 10, " hits: %d\n", run_stats[0].besthits ); /* retrieve the (FILE *) for the .bst and .his files, so that the trees can be printed to them. */ bout = output_filehandle ( OUT_BST ); hout = output_filehandle ( OUT_HIS ); if ( run_stats[0].bestn == 1 ) { oprintf ( OUT_BST, 20, "TOP INDIVIDUAL:\n\n" ); oprintf ( OUT_HIS, 20, "TOP INDIVIDUAL:\n\n" ); } else { oprintf ( OUT_BST, 20, "TOP %d INDIVIDUALS (in order):\n\n", run_stats[0].bestn ); oprintf ( OUT_HIS, 20, "TOP %d INDIVIDUALS (in order):\n\n", run_stats[0].bestn ); } for ( i = 0; i < run_stats[0].bestn; ++i ) { oprintf ( OUT_BST, 20, "\n\n-- #%d --\n", i+1 ); oprintf ( OUT_BST, 20, " hits: %d\n", run_stats[0].best[i]->ind->hits ); oprintf ( OUT_BST, 20, " raw fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->r_fitness ); oprintf ( OUT_BST, 20, " standardized fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->s_fitness ); oprintf ( OUT_BST, 20, " adjusted fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->a_fitness ); oprintf ( OUT_HIS, 20, "\n\n-- #%d --\n", i+1 ); oprintf ( OUT_HIS, 20, " hits: %d\n", run_stats[0].best[i]->ind->hits ); oprintf ( OUT_HIS, 20, " raw fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->r_fitness ); oprintf ( OUT_HIS, 20, " standardized fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->s_fitness ); oprintf ( OUT_HIS, 20, " adjusted fitness: %.*lf\n", fd, run_stats[0].best[i]->ind->a_fitness ); /* print the tree to both files here. */ if ( test_detail_level ( 20 ) ) { pretty_print_individual ( run_stats[0].best[i]->ind, bout ); pretty_print_individual ( run_stats[0].best[i]->ind, hout ); } } /* call the end-of-evaluation callback. returns 1 if user termination criterion is met, 0 otherwise. */ ret = app_end_of_evaluation ( *gen, mpop, newbest, gen_stats, run_stats ); /* close the .bst file. */ output_stream_close ( OUT_BST ); } /* IF COUNT == mpop->size */ #ifdef PDEBUG_GP printf("Finished receive_generation_info()\n"); fflush(stdout); #endif if (stats->count == mpop->size) return stats; return NULL; } /* free_gen_stats() * * frees the memory referred to by gen_stats */ void free_gen_stats (multipop *mpop) { int i, j; for ( i = 0; i < mpop->size+1; ++i ) { for ( j = 0; j < run_stats[i].bestn; ++j ) --run_stats[i].best[j]->refcount; FREE ( run_stats[i].best ); } FREE ( run_stats ); /* deallocate saved individuals that are no longer needed. */ saved_individual_gc(); } /* get_current_generation() * * returns the generation being processed on this node */ int get_current_generation ( void ) { return gen; } /* alloc_popstats_list() * * adds a link in front of the list given as parameter, NO ALLOCATION !!! */ Popstats_list *alloc_popstats_list ( Popstats_list *p ) { char *parameter; Popstats_list *ret; event *e; int number_of_populations; int i; parameter = get_parameter("multiple.subpops"); if (parameter == NULL) error (E_FATAL_ERROR, "get_parameter() failed in alloc_popstats_list()"); number_of_populations = atoi (parameter); ret = (Popstats_list *) MALLOC (sizeof(Popstats_list)); if (ret == NULL) error (E_FATAL_ERROR, "Memory allocation failed in alloc_popstats_list() I"); e = (event *) MALLOC (sizeof(event) * number_of_populations); if (e == NULL) error (E_FATAL_ERROR, "Memory allocation failed in alloc_popstats_list() II"); /* Set some illegal values in the array */ for (i=0; ieval = e; e = (event *) MALLOC (sizeof(event) * number_of_populations); if (e == NULL) error (E_FATAL_ERROR, "Memory allocation failed in alloc_popstats_list() III"); /* Set some illegal values in the array */ for (i=0; ibreeding = e; ret->gen = -9999; ret->count = 0; ret->next = p; return ret; } /* dealloc_popstats_list() * * frees the linked list of population statistics */ void dealloc_popstats_list ( Popstats_list *p, multipop *mpop ) { int i, j; int counter = 0; Popstats_list *tmp; popstats *gen_stats; printf ("Deallocating list of statistics "); while ( p != NULL ) { counter++; tmp = (Popstats_list *) p->next; gen_stats = p->stats; /* Free the statistics */ for (i=0; isize+1; i++) { for ( j = 0; j < gen_stats[i].bestn; ++j ) if ( gen_stats[i].best ) --gen_stats[i].best[j]->refcount; FREE ( gen_stats[i].best ); } FREE(p->stats); FREE(p->eval); FREE(p->breeding); /* Garbage collect the individuals who are not referenced anymore */ saved_individual_gc(); /* Free this link */ FREE(p); /* Move to the next link */ p = tmp; printf ("."); fflush(stdout); } printf (" %d items removed.\n", counter); return; } /* find_popstats() * * find the population statistics for the given generation. If these are not found an additional link * is allocated. */ Popstats_list *find_popstats ( Popstats_list **p, int gen ) { Popstats_list *tmp; /* tmp = *p; while ( tmp != NULL ) { printf ("gen%d #%d ", tmp->gen, tmp->count); fflush(stdout); tmp = (Popstats_list *) tmp->next; } printf("\n"); */ tmp = *p; while ( (tmp != NULL) && (tmp->gen != gen) ) { tmp = (Popstats_list *) tmp->next; } /* Not found in the list so we put a new link in front of the list */ if ( tmp == NULL ) { tmp = *p = alloc_popstats_list(*p); } return tmp; } /* remove_statistics() * * removes a link from the linked list */ Popstats_list *remove_statistics( Popstats_list *l, Popstats_list *p, multipop *mpop ) { int i, j; popstats *gen_stats; Popstats_list *tmp; tmp = l; /* Find the link in the list */ while ( (tmp != NULL) && (tmp->next != p) ) tmp = (Popstats_list *) tmp->next; /* If we found one we delete the information it refers to and reomve if from the list */ if (tmp != NULL) { /* We found it */ /* Change the link */ tmp->next = p->next; /* printf ("Removing stats for generation %d\n", p->gen); */ gen_stats = p->stats; /* Free the statistics */ for (i=0; isize+1; i++) { for ( j = 0; j < gen_stats[i].bestn; ++j ) --gen_stats[i].best[j]->refcount; FREE ( gen_stats[i].best ); } FREE(p->stats); FREE(p->eval); FREE(p->breeding); /* Garbage collect the individuals who are not referenced anymore */ saved_individual_gc(); /* Free this link */ FREE(p); } /* Maybe this was the head of the list */ if (l == p) l = tmp; return l; } #endif