遗传算法中的交叉操作是 对NSGA-II 源码分析的 最后一部分, 这一部分也是我 从读该算法源代码和看该算法论文理解偏差最大的 函数模块。
这里,首先提一下,遗传算法的 交叉操作、变异操作都是需要设定概率的, 即交叉概率和变异概率。
假设种群个体 大小为 popsize , 那么交叉操作需要进行 popsize/2 次 , 变异操作需要进行 popsize 次, 其中每次操作的时候都需要随机生成一个随机数来与给定的概率进行判断,若小于给定的概率则继续执行否则退出该操作。
如果继续操作的话 需要注意一个问题 对两个个体交叉 ,或 对单个个体进行变异 都是对 个体的所有变量 进行操作,其中变异对二进制编码的个体来说是对每个个体的每个变量 的二进制编码的 每个比特位进行变异。
包装函数,通过对标识位判断编码形式来决定 具体的核心功能 所调用的函数。
1 /* Crossover routines */ 2 3 # include <stdio.h> 4 # include <stdlib.h> 5 # include <math.h> 6 7 # include "global.h" 8 # include "rand.h" 9 10 /* Function to cross two individuals */ 11 void crossover (individual *parent1, individual *parent2, individual *child1, individual *child2) 12 { 13 if (nreal!=0) 14 { 15 realcross (parent1, parent2, child1, child2); 16 } 17 if (nbin!=0) 18 { 19 bincross (parent1, parent2, child1, child2); 20 } 21 return; 22 }
实数编码的 两个个体交叉操作, 采用 SBX 方式交叉。需要交叉的两个个体 每个变量 都进行交叉操作。
1 /* Routine for real variable SBX crossover */ 2 void realcross (individual *parent1, individual *parent2, individual *child1, individual *child2) 3 { 4 int i; 5 double rand; 6 double y1, y2, yl, yu; 7 double alpha, beta, betaq; 8 if (randomperc() <= pcross_real) 9 { 10 nrealcross++; 11 for (i=0; i<nreal; i++) 12 { 13 if (randomperc() <= 0.5 ) 14 { 15 if (parent1->xreal[i] < parent2->xreal[i]) 16 { 17 y1 = parent1->xreal[i]; 18 y2 = parent2->xreal[i]; 19 } 20 else 21 { 22 y1 = parent2->xreal[i]; 23 y2 = parent1->xreal[i]; 24 } 25 if (fabs(parent1->xreal[i]-parent2->xreal[i]) > EPS) 26 { 27 yl = min_realvar[i]; 28 yu = max_realvar[i]; 29 rand = randomperc(); 30 beta = 1.0 + (2.0*(y1-yl)/(y2-y1)); 31 alpha = 2.0 - pow(beta,-(eta_c+1.0)); 32 if (rand <= (1.0/alpha)) 33 { 34 betaq = pow ((rand*alpha),(1.0/(eta_c+1.0))); 35 } 36 else 37 { 38 betaq = pow ((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0))); 39 } 40 child1->xreal[i] = 0.5*((y1+y2)-betaq*(y2-y1)); 41 beta = 1.0 + (2.0*(yu-y2)/(y2-y1)); 42 alpha = 2.0 - pow(beta,-(eta_c+1.0)); 43 if (rand <= (1.0/alpha)) 44 { 45 betaq = pow ((rand*alpha),(1.0/(eta_c+1.0))); 46 } 47 else 48 { 49 betaq = pow ((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0))); 50 } 51 child2->xreal[i] = 0.5*((y1+y2)+betaq*(y2-y1)); 52 if (child1->xreal[i]<yl) 53 { 54 child1->xreal[i]=yl; 55 } 56 if (child1->xreal[i]>yu) 57 { 58 child1->xreal[i]=yu; 59 } 60 if (child2->xreal[i]<yl) 61 { 62 child2->xreal[i]=yl; 63 } 64 if (child2->xreal[i]>yu) 65 { 66 child2->xreal[i]=yu; 67 } 68 } 69 else 70 { 71 child1->xreal[i] = parent1->xreal[i]; 72 child2->xreal[i] = parent2->xreal[i]; 73 } 74 } 75 else 76 { 77 child1->xreal[i] = parent1->xreal[i]; 78 child2->xreal[i] = parent2->xreal[i]; 79 } 80 } 81 } 82 else 83 { 84 for (i=0; i<nreal; i++) 85 { 86 child1->xreal[i] = parent1->xreal[i]; 87 child2->xreal[i] = parent2->xreal[i]; 88 } 89 } 90 return; 91 }
二进制编码 的 交叉操作:
(双点 交叉) 两个个体的 每个对应的变量 彼此交叉操作。这里每个变量的 二进制编码 段 随机选取两点, 将中间部门的二进制段 互换,两个交叉点。
1 /* Routine for two point binary crossover */ 2 void bincross (individual *parent1, individual *parent2, individual *child1, individual *child2) 3 { 4 int i, j; 5 double rand; 6 int temp, site1, site2; 7 for (i=0; i<nbin; i++) 8 { 9 rand = randomperc(); 10 if (rand <= pcross_bin) 11 { 12 nbincross++; 13 site1 = rnd(0,nbits[i]-1); 14 site2 = rnd(0,nbits[i]-1); 15 if (site1 > site2) 16 { 17 temp = site1; 18 site1 = site2; 19 site2 = temp; 20 } 21 for (j=0; j<site1; j++) 22 { 23 child1->gene[i][j] = parent1->gene[i][j]; 24 child2->gene[i][j] = parent2->gene[i][j]; 25 } 26 for (j=site1; j<site2; j++) 27 { 28 child1->gene[i][j] = parent2->gene[i][j]; 29 child2->gene[i][j] = parent1->gene[i][j]; 30 } 31 for (j=site2; j<nbits[i]; j++) 32 { 33 child1->gene[i][j] = parent1->gene[i][j]; 34 child2->gene[i][j] = parent2->gene[i][j]; 35 } 36 } 37 else 38 { 39 for (j=0; j<nbits[i]; j++) 40 { 41 child1->gene[i][j] = parent1->gene[i][j]; 42 child2->gene[i][j] = parent2->gene[i][j]; 43 } 44 } 45 } 46 return; 47 }
对于 遗传算法的交叉操作, 有一点是需要注意的 那就是 交叉操作 执行 popsize/2 次, 而且是按照种群个体的排序顺序(按照个体的序号)依次取出两个个体进行交叉操作,而每次执行交叉操作时是否真的进行交叉还要比对随机生成的随机数 与 给定的交叉概率大小 。