libfgen
0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
|
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