libfgen  0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
population.c
00001 /*
00002     population.c -- genetic algorithm population handling functions.
00003 
00004     fgen -- Library for optimization using a genetic algorithm or particle swarm optimization.
00005     Copyright 2012, Harm Hanemaaijer
00006 
00007     This file is part of fgen.
00008 
00009     fgen is free software: you can redistribute it and/or modify it
00010     under the terms of the GNU Lesser General Public License as published
00011     by the Free Software Foundation, either version 3 of the License, or
00012     (at your option) any later version.
00013 
00014     fgen is distributed in the hope that it will be useful, but WITHOUT
00015     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00017     License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public
00020     License along with fgen.  If not, see <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <limits.h>
00028 #include <math.h>
00029 #include <float.h>
00030 #include <pthread.h>
00031 #include "fgen.h"
00032 #include "parameters.h"
00033 #include "bitstring.h"
00034 #include "error.h"
00035 #include "population.h"
00036 #include "cache.h"
00037 #include "win32_compat.h"
00038 
00039 FgenIndividual **AllocatePopulation(FgenPopulation *pop) {
00040         return (FgenIndividual **)malloc(sizeof(FgenIndividual *) * pop->size);
00041 }
00042 
00043 void CreateInitialPopulation(FgenPopulation *pop) {
00044         int i;
00045         if (pop->ind == NULL)
00046                 // Allocate a population.
00047                 pop->ind = AllocatePopulation(pop);
00048         else {
00049                 // A population already exists.
00050                 if (pop->initialization_type == FGEN_INITIALIZATION_CONTINUE) {
00051                         for (int i = 0; i < pop->size; i++)
00052                                 pop->ind[i]->fitness_is_valid = 0;
00053                         return;
00054                 }
00055                 // FGEN_INITIALIZATION_SEED is set; free the individuals.
00056                 FreePopulation(pop, pop->ind);
00057         }
00058         for (i = 0; i < pop->size; i++) {
00059                 pop->ind[i] = NewIndividual(pop);
00060                 pop->fgen_seed_func(pop, pop->ind[i]->bitstring);
00061         }
00062 }
00063 
00064 void CalculateIndividualFitness(FgenPopulation *pop, FgenIndividual *ind) {
00065         double cache_fitness;
00066         int hash;
00067         if (ind->fitness_is_valid) {
00068                 return;
00069         }
00070         if (pop->cache != NULL)
00071                 if (CacheHit(pop, ind, &cache_fitness, &hash)) {
00072                         ind->fitness = cache_fitness;
00073                         ind->fitness_is_valid = 1;
00074                         return;
00075                 }
00076         ind->fitness = pop->fgen_calculate_fitness_func(pop, ind->bitstring);
00077         ind->fitness_is_valid = 1;
00078         if (pop->cache != NULL)
00079                 AddToCache(pop, ind, hash);
00080 }
00081 
00082 void CalculatePopulationFitness(FgenPopulation *pop, double *sum_out,
00083 double *min_fitness_out ) {
00084         int i;
00085         double sum, min_fitness;
00086         sum = 0;
00087         min_fitness = POSITIVE_INFINITY_DOUBLE;
00088         for (i = 0; i < pop->size; i++) {
00089                 CalculateIndividualFitness(pop, pop->ind[i]);
00090                 // Be careful not to overflow on systems were infinity is finite. 
00091                 if (pop->ind[i]->fitness == POSITIVE_INFINITY_DOUBLE)
00092                         sum = POSITIVE_INFINITY_DOUBLE;
00093                 else
00094                         sum += pop->ind[i]->fitness;
00095                 if (pop->ind[i]->fitness < min_fitness)
00096                         min_fitness = pop->ind[i]->fitness;
00097         }
00098         if (sum_out != NULL)
00099                 *sum_out = sum;
00100         if (min_fitness_out != NULL)
00101                 *min_fitness_out = min_fitness;
00102 }
00103 
00104 /* Threaded version. Doesn't work with cache enabled. */
00105 
00106 typedef struct {
00107         FgenPopulation *pop;
00108         int start_index;
00109         int end_index;
00110 } ThreadData;
00111 
00112 static void *CalculatePartPopulationFitness(void *threadarg) {
00113         ThreadData *thread_data = (ThreadData *)threadarg;
00114         FgenPopulation *pop = thread_data->pop;
00115         int i;
00116         for (i = thread_data->start_index; i < thread_data->end_index; i++)
00117                 CalculateIndividualFitness(pop, pop->ind[i]);
00118         return NULL;
00119 }
00120 
00121 void CalculatePopulationFitnessThreaded(FgenPopulation *pop) {
00122         pthread_t *thread;
00123         ThreadData *thread_data;
00124         int i;
00125         thread = (pthread_t *)malloc(sizeof(pthread_t) * pop->max_threads);
00126         thread_data = (ThreadData *)malloc(sizeof(ThreadData) * pop->max_threads);
00127         /* Divide the population into n parts. */
00128         for (i = 0; i < pop->max_threads; i++) {
00129                 thread_data[i].pop = pop;
00130                 thread_data[i].start_index = pop->size * i / pop->max_threads;
00131                 thread_data[i].end_index = pop->size * (i + 1) / pop->max_threads;
00132         }
00133         /* Create the first n - 1 threads. */
00134         for (i = 0; i < pop->max_threads - 1; i++)
00135                 pthread_create(&thread[i], NULL, CalculatePartPopulationFitness, &thread_data[i]);
00136         /* The current thread is the n-th thread. */
00137         CalculatePartPopulationFitness(&thread_data[pop->max_threads - 1]);
00138         /* Wait for the threads to finish. */
00139         for (i = 0; i < pop->max_threads - 1; i++)
00140                 pthread_join(thread[i], NULL);
00141         free(thread_data);
00142         free(thread);
00143 }
00144 
00145 /* Heavily threaded version that creates a new thread for each fitness calculation. */
00146 
00147 typedef struct {
00148         FgenPopulation *pop;
00149         int index;
00150 } ThreadData2;
00151 
00152 void *CalculateIndividualFitnessThreaded(void *threadarg) {
00153         ThreadData2 *thread_data = (ThreadData2 *)threadarg;
00154         FgenPopulation *pop = thread_data->pop;
00155         int index = thread_data->index;
00156         CalculateIndividualFitness(pop, pop->ind[index]);
00157         return NULL;
00158 }
00159 
00160 void CalculatePopulationFitnessHeavilyThreaded(FgenPopulation *pop) {
00161         pthread_t *thread;
00162         int max_threads;
00163         int nu_threads;
00164         int i;
00165         ThreadData2 *thread_data;
00166         max_threads = 8;
00167         thread = (pthread_t *)malloc(sizeof(pthread_t) * max_threads);
00168         thread_data = (ThreadData2 *)malloc(sizeof(ThreadData) * max_threads);
00169         nu_threads = 0;
00170         for (i = 0; i < pop->size; i++) {
00171                 if (pop->ind[i]->fitness_is_valid)
00172                         continue;
00173                 if (nu_threads == max_threads) {
00174                         int j;
00175                         for (j = 0; j < max_threads; j++)
00176                                 pthread_join(thread[j], NULL);
00177                         nu_threads = 0;
00178                 }
00179                 thread_data[nu_threads].pop = pop;
00180                 thread_data[nu_threads].index = i;
00181                 pthread_create(&thread[nu_threads], NULL, CalculateIndividualFitnessThreaded,
00182                         &thread_data[nu_threads]);
00183                 nu_threads++;
00184         }
00185         for (i = 0; i < nu_threads; i++)
00186                 pthread_join(thread[i], NULL);
00187         free(thread);
00188         free(thread_data);
00189 }
00190 
00191 
00192 void CopyIndividualBitstring(FgenPopulation *pop, FgenIndividual *src, FgenIndividual *dest ) {
00193         memcpy(dest->bitstring, src->bitstring, INDIVIDUAL_SIZE_IN_BYTES(pop));
00194 }
00195 
00196 void FreeIndividual(FgenIndividual *ind) {
00197         if (ind->refcount < 1)
00198                 gen_error("FreeIndividual: Reference count already zero.");
00199         ind->refcount--;
00200         if (ind->refcount == 0) {
00201                 free(ind->bitstring);
00202                 free(ind);
00203         }
00204 }
00205 
00206 FgenIndividual *NewIndividual(FgenPopulation *pop) {
00207         FgenIndividual *ind;
00208         ind = (FgenIndividual *)malloc(sizeof(FgenIndividual));
00209         ind->bitstring = (unsigned char *)malloc(INDIVIDUAL_SIZE_IN_BYTES(pop));
00210         ind->fitness_is_valid = 0;
00211         ind->is_elite = 0;
00212         ind->refcount = 1;      /* Assumption. */
00213         return ind;
00214 }
00215 
00216 void FreePopulation(FgenPopulation *pop, FgenIndividual **ind) {
00217         int i;
00218         for (i = 0; i < pop->size; i++)
00219                 FreeIndividual(ind[i]);
00220 }
00221 
00229 FgenIndividual *fgen_best_individual_of_population(FgenPopulation *pop) {
00230         int i, best;
00231         double bestfitness;
00232         CalculatePopulationFitness(pop, NULL, NULL); /* Make sure every fitness is updated. */
00233         bestfitness = NEGATIVE_INFINITY_DOUBLE;
00234         for (i = 0; i < pop->size; i++)
00235                 if (pop->ind[i]->fitness > bestfitness) {
00236                         bestfitness = pop->ind[i]->fitness;
00237                         best = i;
00238                 }
00239         return pop->ind[best];
00240 }
00241 
00249 FgenIndividual *fgen_worst_individual_of_population(FgenPopulation *pop) {
00250         int i, worst;
00251         double worst_fitness;
00252         CalculatePopulationFitness(pop, NULL, NULL); /* Make sure every fitness is updated. */
00253         worst_fitness = POSITIVE_INFINITY_DOUBLE;
00254         for (i = 0; i < pop->size; i++)
00255                 if (pop->ind[i]->fitness < worst_fitness) {
00256                         worst_fitness = pop->ind[i]->fitness;
00257                         worst = i;
00258                 }
00259         return pop->ind[worst];
00260 }
00261 
00272 FgenIndividual *fgen_best_individual_of_archipelago(int nu_pops, FgenPopulation **pops) {
00273         int i;
00274         double best_fitness;
00275         FgenIndividual *best_ind;
00276         best_fitness = NEGATIVE_INFINITY_DOUBLE;
00277         for (i = 0; i < nu_pops; i++) {
00278                 FgenIndividual *ind;
00279                 ind = fgen_best_individual_of_population(pops[i]);
00280                 if (ind->fitness > best_fitness) {
00281                         best_fitness = ind->fitness;
00282                         best_ind = ind;
00283                 }
00284         }
00285         return best_ind;
00286 }
00287 
00292 void fgen_update_population_fitness(FgenPopulation *pop) {
00293         CalculatePopulationFitness(pop, NULL, NULL);
00294 }
00295 
00301 void fgen_invalidate_population_fitness(FgenPopulation *pop) {
00302         int i;
00303         for (i = 0; i < pop->size; i++)
00304                 pop->ind[i]->fitness_is_valid = 0;
00305         if (pop->cache != NULL)
00306                 fgen_invalidate_cache(pop);
00307 }
00308 
00313 int fgen_individual_size_in_bytes(const FgenPopulation *pop) {
00314     return INDIVIDUAL_SIZE_IN_BYTES(pop);
00315 }
00316 
 All Data Structures Functions Variables