libfgen  0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
crossover.c
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 
 All Data Structures Functions Variables