#ifndef lint static char *rcsid = "$Header: /tmp_mnt/vida/disks/disk5/Users/terry/r/gassy/RCS/print_stats.c,v 1.9 1992/10/09 06:43:50 terry Exp terry $"; #endif #include "types.h" #include "utility.h" #include #include VOID print_run_stats(fp, max_possible_fitness, max_fitness_found, context) FILE *fp; FITNESS max_possible_fitness; BOOLEAN max_fitness_found; CONTEXT *context; { register INT i; if (max_fitness_found == TRUE){ fprintf(fp, "An individual with maximum possible fitness ("); print_fitness(fp, 0, max_possible_fitness); fprintf(fp, ") was found in generation %d.\n", context->stats[context->run].best_generation); } else { fprintf(fp, "The best individual had fitness "); print_fitness(fp, 0, context->stats[context->run].best_individual.fitness); fprintf(fp, " and was (first) found in generation %d.\n", context->stats[context->run].best_generation); } fprintf(fp, "It was: "); #if ! defined(APP_INDIVIDUALS_ARE_PRINTABLE_STRINGS) putc('\n', fp); #endif print_individual(fp, &context->stats[context->run].best_individual); putc('\n', fp); return; } VOID print_final_stats(fp, context) FILE *fp; CONTEXT *context; { register INT i; INT best_run; FITNESS best_fitness; best_fitness = WORST_FITNESS; for (i = 1; i <= context->nruns; i++){ if (context->stats[i].best_individual.fitness > best_fitness){ best_fitness = context->stats[i].best_individual.fitness; best_run = i; } } fprintf(fp, "The best individual ever found had fitness "); print_fitness(fp, 0, context->stats[best_run].best_individual.fitness); if (context->nruns == 1){ fprintf(fp, ".\nIt was (first) found in generation %d.\n", context->stats[best_run].best_generation); } else { fprintf(fp, ".\nIt was (first) found in generation %d of run %d.\n", context->stats[best_run].best_generation, best_run); } fprintf(fp, "It was: "); #if ! defined(APP_INDIVIDUALS_ARE_PRINTABLE_STRINGS) putc('\n', fp); #endif print_individual(fp, &context->stats[best_run].best_individual); putc('\n', fp); return; } VOID print_population(fp, how_to_sort, unique, ranks, context) FILE *fp; INT how_to_sort; BOOLEAN unique; INT ranks; CONTEXT *context; { register INT i; POPULATION population = context->population; register INT population_size = context->population_size; register INT population_width = 1 + (INT)log10((DOUBLE)population_size); register INT index = (INT) 0; INT unique_count = (INT) 0; BOOLEAN track_best_fitness = FALSE; sort_population(how_to_sort, context); if (ranks == 0){ ranks = population_size; } else { if (ranks == (INT) 1){ /* No need to sort, we already know the answer. */ print_individual(fp, &population[context->best_individual_of_generation]); fprintf(fp, " with fitness "); print_fitness(fp, 0, population[context->best_individual_of_generation].fitness); fprintf(fp, "\n"); return; } unique = FALSE; } /* * If we are being elitist and the sort is by genome first, then * we need to watch for the index of the best when we do the prinitng * below as it will be lost as a result of the sort. If we are being * elitist and sorting by fitness, we don't have to track it since it * will be in the first location when the sort is done. * * Note that in both these cases, the genome that is considered the * "best" may change. The fitness will not. All we can guarantee is * that we will end up with *some* individual of highest fitness * being considered the best. */ if (context->elitist == TRUE){ switch (how_to_sort){ case BY_GENOME: case BY_GENOME_THEN_BY_FITNESS:{ track_best_fitness = TRUE; break; } case BY_FITNESS: case BY_FITNESS_THEN_BY_GENOME:{ context->best_individual_of_generation = 0; } default:{ /* Nothing to do, there was no sort. */ break; } } } while (index < population_size && (ranks > (INT) 0 || track_best_fitness == TRUE)){ #if defined(APP_NOISY_FITNESS_FUNCTION) register INT last_fitness = population[index].fitness; #endif register STRING last_genome = population[index].genome; register INT starting_index = index++; /* Step over all the next individuals who have the same genome (and fitness, if dynamic). */ while (index < population_size && #if defined(APP_NOISY_FITNESS_FUNCTION) population[index].fitness == last_fitness && #endif !strcmp(population[index].genome, last_genome)){ index++; } if (track_best_fitness == TRUE && population[index].fitness == context->best_fitness_of_generation){ context->best_individual_of_generation = index; track_best_fitness = FALSE; } /* * Now we know that the genomes (and fitnesses, if dynamic) from * population[starting_index] to population[index] are the same. */ /* * There is a miniscule bug here! If the last individual is not * unique, then the last rank printed possibly has less digits * than the number of digits allowed for in population_width. * This means that on RARE occasions, there will be an extra * space in the rank column... This can't be fixed unless we * know ahead of time what the maximum rank will be. But that * would mean doing all this work identifying same-genome * individuals twice - once to find out the largest rank, then * calculating the right width and then doing this stuff again * to print them. Not worth it. This is no longer the perfect * program. */ if (ranks > 0){ if (how_to_sort != NO_SORT){ fprintf(fp, "rank %*d: ", population_width, starting_index + 1); } print_individual(fp, &population[starting_index]); fprintf(fp, " with fitness "); print_fitness(fp, 0, population[starting_index].fitness); if (index - starting_index > 1){ fprintf(fp, " (%d copies)\n", index - starting_index); } else { fprintf(fp, "\n"); } ranks--; } unique_count++; } if (unique == TRUE){ if (unique_count == (INT) 1){ fprintf(fp, "\nThe population contained only one string.\n"); } else { #if defined(APP_NOISY_FITNESS_FUNCTION) fprintf(fp, "\nThe population contained %d unique genome/fitness individuals.\n", unique_count); #else fprintf(fp, "\nThe population contained %d unique individuals.\n", unique_count); #endif } } return; }