libfgen
0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
|
00001 /* 00002 crossover.c -- Crossover stage of the genetic algorithm. 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 <malloc.h> // Added for Visual C++ 00027 #include "string.h" 00028 #include "fgen.h" 00029 #include "parameters.h" 00030 #include "population.h" 00031 #include "random.h" 00032 #include "bitstring.h" 00033 #include "error.h" 00034 00035 00036 /* 00037 * This function performs the Crossover step of the genetic algorithm. 00038 * The populationSize must be a multiple of 2. 00039 */ 00040 00041 void DoCrossover(FgenPopulation *pop) { 00042 int i; 00043 if (pop->crossover_probability == 0 || pop->fgen_crossover_func == fgen_crossover_noop) 00044 return; 00045 FgenIndividual **ind1 = pop->ind; 00046 FgenIndividual **ind2 = AllocatePopulation(pop); 00047 for (i = 0; i < pop->size - 1; i += 2) { 00048 if ((pop->selection_type & FGEN_ELITIST_ELEMENT) && 00049 (ind1[i]->is_elite || ind1[i + 1]->is_elite)) { 00050 ind2[i] = ind1[i]; 00051 ind2[i + 1] = ind1[i + 1]; 00052 /* The following four lines of code have no net effect and can be omitted. */ 00053 /* ind1[i]->refcount++; */ 00054 /* ind1[i + 1]->refcount++; */ 00055 /* FreeIndividual(ind1[i]); */ 00056 /* FreeIndividual(ind1[i + 1]); */ 00057 continue; 00058 } 00059 int r; 00060 r = fgen_random_8(pop->rng); 00061 if (r < pop->crossover_probability) { 00062 /* Perform crossover operation. */ 00063 ind2[i] = NewIndividual(pop); 00064 ind2[i + 1] = NewIndividual(pop); 00065 pop->fgen_crossover_func(pop, ind1[i]->bitstring, ind1[i + 1]->bitstring, ind2[i]->bitstring, 00066 ind2[i + 1]->bitstring); 00067 FreeIndividual(ind1[i]); 00068 FreeIndividual(ind1[i + 1]); 00069 } 00070 else { 00071 /* Assign the unmodified individuals. */ 00072 ind2[i] = ind1[i]; 00073 ind2[i + 1] = ind1[i + 1]; 00074 /* The following four lines of code have no net effect and can be omitted. */ 00075 /* ind1[i]->refcount++; */ 00076 /* ind1[i + 1]->refcount++; */ 00077 /* FreeIndividual(ind1[i]); */ 00078 /* FreeIndividual(ind1[i + 1]); */ 00079 } 00080 } 00081 free(ind1); 00082 pop->ind = ind2; 00083 } 00084 00085 00090 void fgen_crossover_one_point_per_element(FgenPopulation *pop, const unsigned char *parent1, 00091 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00092 int bitnumber; 00093 bitnumber = fgen_random_n(pop->rng, pop->individual_size_in_bits / pop->data_element_size) * 00094 pop->data_element_size; 00095 if (pop->data_element_size == 32 || pop->data_element_size == 64) { 00096 memcpy(child1, parent1, bitnumber / 8); 00097 memcpy(child1 + bitnumber / 8, parent2 + bitnumber / 8, (pop->individual_size_in_bits - bitnumber) / 8); 00098 memcpy(child2, parent2, bitnumber / 8); 00099 memcpy(child2 + bitnumber / 8, parent1 + bitnumber / 8, (pop->individual_size_in_bits - bitnumber) / 8); 00100 return; 00101 } 00102 /* It is quickest to copy the whole string first. */ 00103 memcpy(child1, parent1, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00104 memcpy(child2, parent2, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00105 fgen_copy_partial_bitstring(parent1, child2, bitnumber, 00106 pop->individual_size_in_bits - bitnumber); 00107 fgen_copy_partial_bitstring(parent2, child1, bitnumber, 00108 pop->individual_size_in_bits - bitnumber); 00109 } 00110 00115 void fgen_crossover_one_point_per_bit(FgenPopulation *pop, const unsigned char *parent1, 00116 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00117 int bitnumber; 00118 bitnumber = fgen_random_n(pop->rng, pop->individual_size_in_bits); 00119 /* It is quickest to copy the whole string first. */ 00120 memcpy(child1, parent1, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00121 memcpy(child2, parent2, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00122 fgen_copy_partial_bitstring(parent1, child2, bitnumber, 00123 pop->individual_size_in_bits - bitnumber); 00124 fgen_copy_partial_bitstring(parent2, child1, bitnumber, 00125 pop->individual_size_in_bits - bitnumber); 00126 } 00127 00132 void fgen_crossover_two_point_per_element(FgenPopulation *pop, const unsigned char *parent1, 00133 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00134 /* Exchange the segments that fall between two positions. */ 00135 int bitnumber1, bitnumber2; 00136 bitnumber1 = fgen_random_n(pop->rng, pop->individual_size_in_bits / pop->data_element_size) * 00137 pop->data_element_size; 00138 bitnumber2 = fgen_random_n(pop->rng, pop->individual_size_in_bits / pop->data_element_size) * 00139 pop->data_element_size; 00140 if (bitnumber1 > bitnumber2) { 00141 int temp; 00142 temp = bitnumber1; 00143 bitnumber1 = bitnumber2; 00144 bitnumber2 = temp; 00145 } 00146 if (pop->data_element_size == 32 || pop->data_element_size == 64) { 00147 memcpy(child1, parent1, bitnumber1 / 8); 00148 memcpy(child1 + bitnumber1 / 8, parent2 + bitnumber1 / 8, (bitnumber2 - bitnumber1) / 8); 00149 memcpy(child1 + bitnumber2 / 8, parent1 + bitnumber2 / 8, (pop->individual_size_in_bits - bitnumber2) / 8); 00150 memcpy(child2, parent2, bitnumber1 / 8); 00151 memcpy(child2 + bitnumber1 / 8, parent1 + bitnumber1 / 8, (bitnumber2 - bitnumber1) / 8); 00152 memcpy(child2 + bitnumber2 / 8, parent2 + bitnumber2 / 8, (pop->individual_size_in_bits - bitnumber2) / 8); 00153 return; 00154 } 00155 /* It is quickest to copy the whole string first. */ 00156 memcpy(child1, parent1, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00157 memcpy(child2, parent2, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00158 fgen_copy_partial_bitstring(parent1, child2, bitnumber1, 00159 bitnumber2 - bitnumber1); 00160 fgen_copy_partial_bitstring(parent2, child1, bitnumber1, 00161 bitnumber2 - bitnumber1); 00162 } 00163 00168 void fgen_crossover_two_point_per_bit(FgenPopulation *pop, const unsigned char *parent1, 00169 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00170 /* Exchange the segments that fall between two positions. */ 00171 int bitnumber1, bitnumber2; 00172 bitnumber1 = fgen_random_n(pop->rng, pop->individual_size_in_bits); 00173 bitnumber2 = fgen_random_n(pop->rng, pop->individual_size_in_bits); 00174 if (bitnumber1 > bitnumber2) { 00175 int temp; 00176 temp = bitnumber1; 00177 bitnumber1 = bitnumber2; 00178 bitnumber2 = temp; 00179 } 00180 /* It is quickest to copy the whole string first. */ 00181 memcpy(child1, parent1, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00182 memcpy(child2, parent2, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00183 fgen_copy_partial_bitstring(parent1, child2, bitnumber1, 00184 bitnumber2 - bitnumber1); 00185 fgen_copy_partial_bitstring(parent2, child1, bitnumber1, 00186 bitnumber2 - bitnumber1); 00187 } 00188 00193 void fgen_crossover_uniform_per_bit(FgenPopulation *pop, const unsigned char *parent1, 00194 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00195 /* Randomly select the parent for each bit. */ 00196 /* pop->individual_size_in_bits is assumed to be multiple of 8. */ 00197 unsigned char *srcstr1, *srcstr2; 00198 unsigned char *deststr1, *deststr2; 00199 int i; 00200 srcstr1 = (unsigned char *)parent1; 00201 srcstr2 = (unsigned char *)parent2; 00202 deststr1 = child1; 00203 deststr2 = child2; 00204 for (i = 0; i < INDIVIDUAL_SIZE_IN_BYTES(pop); i++) { 00205 unsigned int srcbyte1, srcbyte2; 00206 unsigned int destbyte1, destbyte2; 00207 srcbyte1 = srcstr1[i]; 00208 srcbyte2 = srcstr2[i]; 00209 destbyte1 = 0x00; 00210 destbyte2 = 0x00; 00211 #if 0 00212 int mask = 1; 00213 for (j = 0; j < 8; j++) { 00214 if (Random2()) { 00215 destbyte1 |= srcbyte1 & mask; 00216 destbyte2 |= srcbyte2 & mask; 00217 } 00218 else { 00219 destbyte1 |= srcbyte2 & mask; 00220 destbyte2 |= srcbyte1 & mask; 00221 } 00222 mask <<= 1; 00223 } 00224 #else 00225 int r = fgen_random_8(pop->rng); 00226 int mask; 00227 for (mask = 1; mask <= 0x80; mask <<= 1) { 00228 destbyte1 |= (srcbyte1 & mask) & (r & mask); 00229 destbyte2 |= (srcbyte2 & mask) & (r & mask); 00230 destbyte1 |= (srcbyte2 & mask) & ((r & mask) ^ mask); 00231 destbyte2 |= (srcbyte1 & mask) & ((r & mask) ^ mask); 00232 } 00233 #endif 00234 deststr1[i] = destbyte1; 00235 deststr2[i] = destbyte2; 00236 } 00237 } 00238 00244 void fgen_crossover_uniform_per_element(FgenPopulation *pop, const unsigned char *parent1, 00245 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00246 /* Randomly select the parent for each data element. */ 00247 /* pop->individual_size_in_bits is assumed to be multiple of pop->data_element_size. */ 00248 if (pop->data_element_size == 32) { 00249 unsigned int *p1 = (unsigned int *)parent1; 00250 unsigned int *p2 = (unsigned int *)parent2; 00251 unsigned int *c1 = (unsigned int *)child1; 00252 unsigned int *c2 = (unsigned int *)child2; 00253 for (int i = 0; i < pop->individual_size_in_bits / 32; i++) { 00254 int r = fgen_random_2(pop->rng); 00255 if (r == 0) { 00256 /* Swap. */ 00257 c1[i] = p2[i]; 00258 c2[i] = p1[i]; 00259 } 00260 else { 00261 c1[i] = p1[i]; 00262 c2[i] = p2[i]; 00263 } 00264 } 00265 return; 00266 } 00267 if (pop->data_element_size == 64) { 00268 unsigned int *p1 = (unsigned int *)parent1; 00269 unsigned int *p2 = (unsigned int *)parent2; 00270 unsigned int *c1 = (unsigned int *)child1; 00271 unsigned int *c2 = (unsigned int *)child2; 00272 for (int i = 0; i < pop->individual_size_in_bits / 32; i += 2) { 00273 int r = fgen_random_2(pop->rng); 00274 if (r == 0) { 00275 /* Swap. */ 00276 c1[i] = p2[i]; 00277 c1[i + 1] = p2[i + 1]; 00278 c2[i] = p1[i]; 00279 c2[i + 1] = p1[i + 1]; 00280 } 00281 else { 00282 c1[i] = p1[i]; 00283 c1[i + 1] = p1[i + 1]; 00284 c2[i] = p2[i]; 00285 c2[i + 1] = p2[i + 1]; 00286 } 00287 } 00288 return; 00289 } 00290 for (int i = 0; i < pop->individual_size_in_bits; i += pop->data_element_size) { 00291 int r = fgen_random_2(pop->rng); 00292 if (r == 0) { 00293 /* Swap this element. */ 00294 fgen_copy_partial_bitstring(parent2, child1, i, pop->data_element_size); 00295 fgen_copy_partial_bitstring(parent1, child2, i, pop->data_element_size); 00296 } 00297 else { 00298 /* Copy elements unchanged. */ 00299 fgen_copy_partial_bitstring(parent1, child1, i, pop->data_element_size); 00300 fgen_copy_partial_bitstring(parent2, child2, i, pop->data_element_size); 00301 } 00302 } 00303 } 00304 00309 void fgen_crossover_permutation_order_based(FgenPopulation *pop, const unsigned char *parent1, 00310 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00311 const int *p1 = (int *)parent1; 00312 const int *p2 = (int *)parent2; 00313 int *c1 = (int *)child1; 00314 int *c2 = (int *)child2; 00315 // Pick a random subroute of random size. 00316 int index = fgen_random_n(pop->rng, pop->permutation_size); 00317 int max_size = pop->permutation_size - index; 00318 int size; 00319 if (max_size == pop->permutation_size) 00320 size = fgen_random_n(pop->rng, pop->permutation_size - 1) + 1; 00321 else 00322 if (max_size > 1) 00323 size = fgen_random_n(pop->rng, max_size) + 1; 00324 else 00325 size = 1; 00326 // Copy the subroute from parent 1 to the same location in child 1. 00327 memcpy(c1 + index, p1 + index, size * 4); 00328 // Mark out elements in parent 2 that exist in the subroute. 00329 int *skip = (int *)alloca(pop->permutation_size * sizeof(int)); 00330 for (int i = 0; i < pop->permutation_size; i++) 00331 skip[i] = 0; 00332 for (int i = index; i < index + size; i++) 00333 skip[p1[i]] = 1; 00334 // Starting on the right side of the subroute, take elements from parent 2 and insert them at the right side 00335 // of the subroute in child 1, skipping elements in parent 2 that were marked out. 00336 int i = index + size; 00337 int j = index + size; 00338 if (j == pop->permutation_size) 00339 j = 0; 00340 for (;;) { 00341 if (i == pop->permutation_size) 00342 i = 0; 00343 if (!skip[p2[i]]) { 00344 c1[j] = p2[i]; 00345 j++; 00346 if (j == pop->permutation_size) 00347 j = 0; 00348 if (j == index) 00349 break; 00350 } 00351 i++; 00352 } 00353 // Now do the same for the second child. 00354 // Copy the subroute from parent 2 to the same location in child 2. 00355 memcpy(c2 + index, p2 + index, size * 4); 00356 // Mark out elements in parent 1 that exist in the subroute. 00357 for (int i = 0; i < pop->permutation_size; i++) 00358 skip[i] = 0; 00359 for (int i = index; i < index + size; i++) 00360 skip[p2[i]] = 1; 00361 // Starting on the right side of the subroute, take elements from parent 1 and insert them at the right side 00362 // of the subroute in child 2, skipping elements in parent 1 that were marked out. 00363 i = index + size; 00364 j = index + size; 00365 if (j == pop->permutation_size) 00366 j = 0; 00367 for (;;) { 00368 if (i == pop->permutation_size) 00369 i = 0; 00370 if (!skip[p1[i]]) { 00371 c2[j] = p1[i]; 00372 j++; 00373 if (j == pop->permutation_size) 00374 j = 0; 00375 if (j == index) 00376 break; 00377 } 00378 i++; 00379 } 00380 } 00381 00382 static inline int TestNumber(const int *perm, int size, int value) { 00383 int i; 00384 for (i = 0; i < size; i++) { 00385 if (perm[i] == value) 00386 return 1; 00387 } 00388 return 0; 00389 } 00390 00395 void fgen_crossover_permutation_position_based(FgenPopulation *pop, const unsigned char *parent1, 00396 const unsigned char *parent2, unsigned char *child1, unsigned char *child2) { 00397 int i; 00398 const int *p1 = (int *)parent1; 00399 const int *p2 = (int *)parent2; 00400 int *c1 = (int *)child1; 00401 int *c2 = (int *)child2; 00402 int pos_c1; 00403 int pos_c2; 00404 int size = pop->permutation_size; 00405 for (i = 0; i < size; i++) { 00406 c1[i] = - 1; 00407 c2[i] = - 1; 00408 } 00409 /* Pick a set of random cities. */ 00410 int pos = fgen_random_n(pop->rng, size - 2); 00411 /* Keep adding random cities until we can add no more. Copy the selected cities into the offspring. */ 00412 while (pos < size) { 00413 c1[pos] = p1[pos]; 00414 c2[pos] = p2[pos]; 00415 pos += fgen_random_n(pop->rng, size - pos) + 1; 00416 } 00417 /* Fill in the blanks. First create two position markers so that we know where we are in */ 00418 /* c1 and c2. */ 00419 pos_c1 = 0; 00420 pos_c2 = 0; 00421 for (i = 0; i < size; i++) { 00422 /* Advance position marker until we reach a free position in c2. */ 00423 while (pos_c2 < size && c2[pos_c2] != - 1) 00424 pos_c2++; 00425 /* c2 get the next city from p1 which is not already present. */ 00426 if (!TestNumber(c2, size, p1[i])) 00427 c2[pos_c2] = p1[i]; 00428 /* Do the same for c1. */ 00429 while (pos_c1 < size && c1[pos_c1] != - 1) 00430 pos_c1++; 00431 /* c1 get the next city from p2 which is not already present. */ 00432 if (!TestNumber(c1, size, p2[i])) 00433 c1[pos_c1] = p2[i]; 00434 } 00435 } 00436 00441 void fgen_crossover_noop(FgenPopulation *pop, const unsigned char *parent1, const unsigned char *parent2, 00442 unsigned char *child1, unsigned char *child2) { 00443 memcpy(child1, parent1, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00444 memcpy(child2, parent2, INDIVIDUAL_SIZE_IN_BYTES(pop)); 00445 } 00446