libfgen
0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
|
00001 00002 /* 00003 mutation.c -- Genetic algorithm mutation implementation. 00004 00005 fgen -- Library for optimization using a genetic algorithm or particle swarm optimization. 00006 Copyright 2012, Harm Hanemaaijer 00007 00008 This file is part of fgen. 00009 00010 fgen is free software: you can redistribute it and/or modify it 00011 under the terms of the GNU Lesser General Public License as published 00012 by the Free Software Foundation, either version 3 of the License, or 00013 (at your option) any later version. 00014 00015 fgen is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00017 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00018 License for more details. 00019 00020 You should have received a copy of the GNU Lesser General Public 00021 License along with fgen. If not, see <http://www.gnu.org/licenses/>. 00022 00023 */ 00024 00025 00026 #include <stdlib.h> 00027 #include <stdio.h> 00028 #include <string.h> 00029 #include <math.h> 00030 #include <float.h> 00031 #include <pthread.h> 00032 #include "fgen.h" /* General includes. */ 00033 #include "parameters.h" 00034 #include "population.h" /* Module includes. */ 00035 #include "bitstring.h" 00036 #include "random.h" 00037 #include "win32_compat.h" 00038 00039 #ifndef __GNUC__ 00040 00041 // Log-gamma code was taken from the following source: 00042 // Visit http://www.johndcook.com/stand_alone_code.html for the source of this code and more like it. 00043 00044 double LogGamma(double x); 00045 00046 static double Gamma 00047 ( 00048 double x // We require x > 0 00049 ) 00050 { 00051 00052 // Split the function domain into three intervals: 00053 // (0, 0.001), [0.001, 12), and (12, infinity) 00054 00056 // First interval: (0, 0.001) 00057 // 00058 // For small x, 1/Gamma(x) has power series x + gamma x^2 - ... 00059 // So in this range, 1/Gamma(x) = x + gamma x^2 with error on the order of x^3. 00060 // The relative error over this interval is less than 6e-7. 00061 00062 const double gamma = 0.577215664901532860606512090; // Euler's gamma constant 00063 00064 if (x < 0.001) 00065 return 1.0/(x*(1.0 + gamma*x)); 00066 00068 // Second interval: [0.001, 12) 00069 00070 if (x < 12.0) 00071 { 00072 // The algorithm directly approximates gamma over (1,2) and uses 00073 // reduction identities to reduce other arguments to this interval. 00074 00075 double y = x; 00076 int n = 0; 00077 bool arg_was_less_than_one = (y < 1.0); 00078 00079 // Add or subtract integers as necessary to bring y into (1,2) 00080 // Will correct for this below 00081 if (arg_was_less_than_one) 00082 { 00083 y += 1.0; 00084 } 00085 else 00086 { 00087 n = static_cast<int> (floor(y)) - 1; // will use n later 00088 y -= n; 00089 } 00090 00091 // numerator coefficients for approximation over the interval (1,2) 00092 static const double p[] = 00093 { 00094 -1.71618513886549492533811E+0, 00095 2.47656508055759199108314E+1, 00096 -3.79804256470945635097577E+2, 00097 6.29331155312818442661052E+2, 00098 8.66966202790413211295064E+2, 00099 -3.14512729688483675254357E+4, 00100 -3.61444134186911729807069E+4, 00101 6.64561438202405440627855E+4 00102 }; 00103 00104 // denominator coefficients for approximation over the interval (1,2) 00105 static const double q[] = 00106 { 00107 -3.08402300119738975254353E+1, 00108 3.15350626979604161529144E+2, 00109 -1.01515636749021914166146E+3, 00110 -3.10777167157231109440444E+3, 00111 2.25381184209801510330112E+4, 00112 4.75584627752788110767815E+3, 00113 -1.34659959864969306392456E+5, 00114 -1.15132259675553483497211E+5 00115 }; 00116 00117 double num = 0.0; 00118 double den = 1.0; 00119 int i; 00120 00121 double z = y - 1; 00122 for (i = 0; i < 8; i++) 00123 { 00124 num = (num + p[i])*z; 00125 den = den*z + q[i]; 00126 } 00127 double result = num/den + 1.0; 00128 00129 // Apply correction if argument was not initially in (1,2) 00130 if (arg_was_less_than_one) 00131 { 00132 // Use identity gamma(z) = gamma(z+1)/z 00133 // The variable "result" now holds gamma of the original y + 1 00134 // Thus we use y-1 to get back the orginal y. 00135 result /= (y-1.0); 00136 } 00137 else 00138 { 00139 // Use the identity gamma(z+n) = z*(z+1)* ... *(z+n-1)*gamma(z) 00140 for (i = 0; i < n; i++) 00141 result *= y++; 00142 } 00143 00144 return result; 00145 } 00146 00148 // Third interval: [12, infinity) 00149 00150 if (x > 171.624) 00151 { 00152 // Correct answer too large to display. Force +infinity. 00153 double temp = DBL_MAX; 00154 // return temp*2.0; 00155 return temp; 00156 } 00157 00158 return exp(LogGamma(x)); 00159 } 00160 00161 static double LogGamma 00162 ( 00163 double x // x must be positive 00164 ) 00165 { 00166 00167 if (x < 12.0) 00168 { 00169 return log(fabs(Gamma(x))); 00170 } 00171 00172 // Abramowitz and Stegun 6.1.41 00173 // Asymptotic series should be good to at least 11 or 12 figures 00174 // For error analysis, see Whittiker and Watson 00175 // A Course in Modern Analysis (1927), page 252 00176 00177 static const double c[8] = 00178 { 00179 1.0/12.0, 00180 -1.0/360.0, 00181 1.0/1260.0, 00182 -1.0/1680.0, 00183 1.0/1188.0, 00184 -691.0/360360.0, 00185 1.0/156.0, 00186 -3617.0/122400.0 00187 }; 00188 double z = 1.0/(x*x); 00189 double sum = c[7]; 00190 for (int i=6; i >= 0; i--) 00191 { 00192 sum *= z; 00193 sum += c[i]; 00194 } 00195 double series = sum/x; 00196 00197 static const double halfLogTwoPi = 0.91893853320467274178032973640562; 00198 double logGamma = (x - 0.5)*log(x) - x + halfLogTwoPi + series; 00199 return logGamma; 00200 } 00201 00202 #define lgamma(x) LogGamma(x) 00203 00204 #endif 00205 00206 /* Avoid function calls to fgen_mutate_bit. */ 00207 #define mutate_bit(bitstring, bitnumber) bitstring[bitnumber / 8] ^= 1 << (bitnumber & 7); 00208 00209 static double BinomialCoefficient(int n, int k) { 00210 return exp(lgamma(n + 1) - lgamma(k + 1) - lgamma(n - k + 1)); 00211 } 00212 00213 /* 00214 * This function is called at the beginning of fgen_run and variants. It sets up an array of probabilities of 00215 * how many bits in an individual will be mutated. 00216 */ 00217 00218 void SetupFastMutationCumulativeChanceArray(FgenPopulation *pop) { 00219 if (pop->fast_mutation_cumulative_chance != NULL) { 00220 // There is already a table present. 00221 if (pop->mutation_probability_float == pop->fast_mutation_probability) 00222 // We have already calculated the table for the right probability. 00223 return; 00224 // Otherwise, overwrite the existing table. 00225 } 00226 else 00227 // There was no table yet. 00228 pop->fast_mutation_cumulative_chance = (float *)malloc(pop->individual_size_in_bits * sizeof(float)); 00229 /* Calculate the chance that one or more bits are mutated in an individual. Equal to one minus the */ 00230 /* minus the chance that no bits are mutated. */ 00231 pop->fast_mutation_cumulative_chance[0] = 00232 1.0 - pow(1.0 - pop->mutation_probability_float, pop->individual_size_in_bits); 00233 // printf("Probability %d bits or more mutated: %lf\n", 1, pop->fast_mutation_cumulative_chance[0]); 00234 for (int i = 1; i < pop->individual_size_in_bits; i++) { 00235 /* Calculate the chance that exactly i bits are mutated in an individual. */ 00236 float f = BinomialCoefficient(pop->individual_size_in_bits, i) * 00237 pow(pop->mutation_probability_float, i) * 00238 pow(1.0 - pop->mutation_probability_float, pop->individual_size_in_bits - i); 00239 if (isnan(f)) 00240 pop->fast_mutation_cumulative_chance[i] = 0; 00241 else 00242 /* Assign the chance that more than i bits are mutated. */ 00243 pop->fast_mutation_cumulative_chance[i] = pop->fast_mutation_cumulative_chance[i - 1] - f; 00244 // printf("Probability %d bits or more mutated: %lf\n", i + 1, pop->fast_mutation_cumulative_chance[i]); 00245 if (pop->fast_mutation_cumulative_chance[i] <= 0.000001) { 00246 if (i < pop->individual_size_in_bits - 1) 00247 pop->fast_mutation_cumulative_chance[i + 1] = 0; 00248 // printf("Probability %d bits or more mutated: %lf\n", i + 2, 00249 // pop->fast_mutation_cumulative_chance[i + 1]); 00250 break; 00251 } 00252 } 00253 pop->fast_mutation_probability = pop->mutation_probability_float; 00254 } 00255 00256 static int NumberOfBitsToMutate(FgenPopulation *pop) { 00257 float f = fgen_random_f(pop->rng, 1.0); 00258 int n = 0; 00259 while (f < pop->fast_mutation_cumulative_chance[n]) 00260 n++; 00261 return n; 00262 } 00263 00264 /* 00265 * This function performs the Mutation step of the genetic algorithm. 00266 */ 00267 00268 void DoMutation(FgenPopulation *pop) { 00269 int i; 00270 FgenIndividual **ind1 = pop->ind; 00271 FgenIndividual **ind2 = AllocatePopulation(pop); 00272 if (pop->fgen_mutation_func == fgen_mutation_per_bit_fast || 00273 pop->fgen_mutation_func == fgen_mutation_per_bit_plus_macro_mutation_fast) { 00274 for (i = 0; i < pop->size; i++) { 00275 if ((pop->selection_type & FGEN_ELITIST_ELEMENT) && ind1[i]->is_elite) { 00276 ind2[i] = ind1[i]; 00277 /* The following two lines of code have no net effect so can be omitted. */ 00278 /* ind1[i]->refcount++; */ 00279 /* FreeIndividual(ind1[i]); */ 00280 continue; 00281 } 00282 int n = NumberOfBitsToMutate(pop); 00283 if (n == 0 && pop->fgen_mutation_func == fgen_mutation_per_bit_fast) 00284 ind2[i] = ind1[i]; 00285 else { 00286 ind2[i] = NewIndividual(pop); 00287 CopyIndividualBitstring(pop, ind1[i], ind2[i]); 00288 pop->fast_mutation_nu_bits_to_mutate = n; 00289 pop->fgen_mutation_func(pop, ind1[i]->bitstring, ind2[i]->bitstring); 00290 FreeIndividual(ind1[i]); 00291 } 00292 } 00293 } 00294 else { 00295 for (i = 0; i < pop->size; i++) { 00296 if ((pop->selection_type & FGEN_ELITIST_ELEMENT) && ind1[i]->is_elite) { 00297 ind2[i] = ind1[i]; 00298 /* The following two lines of code have no net effect so can be omitted. */ 00299 /* ind1[i]->refcount++; */ 00300 /* FreeIndividual(ind1[i]); */ 00301 continue; 00302 } 00303 ind2[i] = NewIndividual(pop); 00304 CopyIndividualBitstring(pop, ind1[i], ind2[i]); 00305 pop->fgen_mutation_func(pop, ind1[i]->bitstring, ind2[i]->bitstring); 00306 FreeIndividual(ind1[i]); 00307 } 00308 } 00309 free(ind1); 00310 pop->ind = ind2; 00311 } 00312 00317 void fgen_mutation_per_bit(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) { 00318 int i; 00319 for (i = 0; i < pop->individual_size_in_bits; i++) { 00320 int r = fgen_random_16(pop->rng); 00321 if (r < pop->mutation_probability) { 00322 /* Mutate the bit. */ 00323 mutate_bit(child, i); 00324 } 00325 } 00326 } 00327 00333 void fgen_mutation_per_bit_fast(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) { 00334 int i; 00335 for (i = 0; i < pop->fast_mutation_nu_bits_to_mutate; i++) { 00336 int r = fgen_random_n(pop->rng, pop->individual_size_in_bits); 00337 mutate_bit(child, r); 00338 } 00339 } 00340 00346 void fgen_mutation_per_bit_plus_macro_mutation(FgenPopulation *pop, const unsigned char *parent, 00347 unsigned char *child) { 00348 fgen_mutation_per_bit(pop, parent, child); 00349 if (pop->macro_mutation_probability > 0) { 00350 int i; 00351 /* For each data element. */ 00352 int n = pop->individual_size_in_bits / pop->data_element_size; 00353 for (i = 0; i < n; i++) { 00354 int r = fgen_random_16(pop->rng); 00355 if (r < pop->macro_mutation_probability) 00356 /* Mutate the entire data element with a random value */ 00357 CreateRandomBitstring(pop->rng, child + i * pop->data_element_size / 8, 00358 pop->data_element_size / 8); 00359 } 00360 } 00361 } 00362 00369 void fgen_mutation_per_bit_plus_macro_mutation_fast(FgenPopulation *pop, const unsigned char *parent, 00370 unsigned char *child) { 00371 fgen_mutation_per_bit_fast(pop, parent, child); 00372 if (pop->macro_mutation_probability > 0) { 00373 if (pop->data_element_size == 32) { 00374 int n = pop->individual_size_in_bits / 32; 00375 for (int i = 0; i < n; i++) { 00376 int r = fgen_random_16(pop->rng); 00377 if (r < pop->macro_mutation_probability) 00378 *(unsigned int *)&child[i * 4] = fgen_random_32(pop->rng); 00379 } 00380 return; 00381 } 00382 if (pop->data_element_size == 64) { 00383 int n = pop->individual_size_in_bits / 32; 00384 for (int i = 0; i < n; i += 2) { 00385 int r = fgen_random_16(pop->rng); 00386 if (r < pop->macro_mutation_probability) { 00387 *(unsigned int *)&child[i * 4] = fgen_random_32(pop->rng); 00388 *(unsigned int *)&child[i * 4 + 4] = fgen_random_32(pop->rng); 00389 } 00390 } 00391 return; 00392 } 00393 /* For each data element. */ 00394 int n = pop->individual_size_in_bits / pop->data_element_size; 00395 for (int i = 0; i < n; i++) { 00396 int r = fgen_random_16(pop->rng); 00397 if (r < pop->macro_mutation_probability) 00398 /* Mutate the entire data element with a random value */ 00399 CreateRandomBitstring(pop->rng, child + i * pop->data_element_size / 8, 00400 pop->data_element_size / 8); 00401 } 00402 } 00403 } 00404 00409 void fgen_mutation_permutation_swap(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) { 00410 int index1, index2; 00411 int r = fgen_random_16(pop->rng); 00412 if (r >= pop->mutation_probability) 00413 return; 00414 do { 00415 index1 = fgen_random_n(pop->rng, pop->permutation_size); 00416 index2 = fgen_random_n(pop->rng, pop->permutation_size); 00417 } while (index1 == index2); 00418 *(int *)&child[index1 * 4] = *(int *)&parent[index2 * 4]; 00419 *(int *)&child[index2 * 4] = *(int *)&parent[index1 * 4]; 00420 } 00421 00427 void fgen_mutation_permutation_insert(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) { 00428 int r = fgen_random_16(pop->rng); 00429 if (r >= pop->mutation_probability) 00430 return; 00431 int index = fgen_random_n(pop->rng, pop->permutation_size); 00432 int index_dest = fgen_random_n(pop->rng, pop->permutation_size); 00433 if (index_dest < index) { 00434 /* The destination of the element is to the left of its previous position. */ 00435 /* The first, unaltered part of the permutation was already copied into the child. */ 00436 /* The second part is the inserted element. */ 00437 *(int *)&child[index_dest * 4] = *(int *)&parent[index * 4]; 00438 /* The third part is the part of the parent up to the element location. */ 00439 memcpy(child + (index_dest + 1) * 4, parent + index_dest * 4, (index - index_dest) * 4); 00440 /* The fourth, unaltered part of the permutation was already copied into the child. */ 00441 } 00442 if (index_dest > index) { 00443 /* The destination of the element is to the right of it previous position. */ 00444 /* The first, unaltered part of the permutation was already copied into the child. */ 00445 /* The second part is the part of the parent to the right of the element, up to destination location. */ 00446 memcpy(child + index * 4, parent + (index + 1) * 4, (index_dest - index) * 4); 00447 /* The third part is the inserted element. */ 00448 *(int *)&child[index_dest * 4] = *(int *)&parent[index * 4]; 00449 /* The fourth, unaltered part of the permutation was already copied into the child. */ 00450 } 00451 /* If the destination is the same as the source location, nothing happens (the child already contains a copy). */ 00452 } 00453 00458 void fgen_mutation_permutation_invert(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) { 00459 int r = fgen_random_16(pop->rng); 00460 if (r >= pop->mutation_probability) 00461 return; 00462 const int *p = (int *)parent; 00463 int *c = (int *)child; 00464 int index = fgen_random_n(pop->rng, pop->permutation_size); 00465 int max_size = pop->permutation_size - index; 00466 int size; 00467 if (max_size > 1) 00468 size = fgen_random_n(pop->rng, max_size) + 1; 00469 else 00470 size = 1; 00471 /* Invert the subroute. */ 00472 for (int i = index; i < index + size; i++) { 00473 c[i] = p[index + size - 1 - (i - index)]; 00474 } 00475 } 00476 00477 /* 00478 * Mutation, threaded version. 00479 * It is slower, and may not be safe. Not used at the moment. 00480 */ 00481 00482 typedef struct { 00483 FgenPopulation *pop; 00484 FgenIndividual **ind2; 00485 int start_index; 00486 int end_index; 00487 } ThreadData; 00488 00489 void *DoMutationPartThread(void *threadarg) { 00490 ThreadData *thread_data = (ThreadData *)threadarg; 00491 FgenPopulation *pop = thread_data->pop; 00492 FgenIndividual **ind2 = thread_data->ind2; 00493 int start_index = thread_data->start_index; 00494 int end_index = thread_data->end_index; 00495 FgenIndividual **ind1 = pop->ind; 00496 int i; 00497 for (i = start_index; i < end_index; i++) { 00498 if ((pop->selection_type & FGEN_ELITIST_ELEMENT) && ind1[i]->is_elite) { 00499 ind2[i] = ind1[i]; 00500 ind1[i]->refcount++; /* Is this safe? */ 00501 continue; 00502 } 00503 ind2[i] = NewIndividual(pop); 00504 CopyIndividualBitstring(pop, ind1[i], ind2[i]); 00505 pop->fgen_mutation_func(pop, ind1[i]->bitstring, ind2[i]->bitstring); 00506 } 00507 return NULL; 00508 } 00509 00510 void DoMutationThreaded(FgenPopulation *pop) { 00511 ThreadData *thread_data; 00512 pthread_t *thread; 00513 int max_threads; 00514 FgenIndividual **ind2; 00515 int i; 00516 max_threads = 2; 00517 thread = (pthread_t *)malloc(sizeof(pthread_t) * max_threads); 00518 thread_data = (ThreadData *)malloc(sizeof(ThreadData) * max_threads); 00519 ind2 = AllocatePopulation(pop); 00520 /* Do the first half. */ 00521 thread_data[0].pop = pop; 00522 thread_data[0].ind2 = ind2; 00523 thread_data[0].start_index = 0; 00524 thread_data[0].end_index = pop->size / 2; 00525 pthread_create(&thread[0], NULL, DoMutationPartThread, &thread_data[0]); 00526 /* Do the second half. */ 00527 thread_data[1].pop = pop; 00528 thread_data[1].ind2 = ind2; 00529 thread_data[1].start_index = pop->size / 2; 00530 thread_data[1].end_index = pop->size; 00531 DoMutationPartThread(&thread_data[1]); 00532 pthread_join(thread[0], NULL); 00533 for (i = 0; i < pop->size; i++) 00534 FreeIndividual(pop->ind[i]); 00535 free(thread_data); 00536 free(thread); 00537 free(pop->ind); 00538 pop->ind = ind2; 00539 } 00540