创建种群的代码3--繁殖
2022-08-14 本文已影响0人
大龙10
书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
第9章目录
9.7 创建种群的代码3
第3步:繁殖
-
交配池已经准备好了,下面我们要开始新个体的繁殖。
首先要选择双亲,我们可以用随机的方式选择它们,这符合生物繁殖的特征,传统GA也是采用这种方式。
但对我们而言,选择父本并没有任何限制:可以用“无性”繁殖的方式实现,也可以选择3个或4个父本合成子代DNA。
在代码演示中,我想用两个父本,并分别称为parentA和parentB。 -
首先,我们要生成两个随机数作为交配池的下标,这是一个介于0至ArrayList长度之间的随机数。
int a = int(random(matingPool.size()));
int b = int(random(matingPool.size()));
- 接下来,我们从交配池中取出这两个下标对应的DNA对象。
DNA parentA = matingPool.get(a);
DNA parentB = matingPool.get(b);
- 交配池中的同一个对象可能会有多个实例(我们也肯重复选中某个随机数),因此parentA和parentB可能是同一个DNA对象。如果要严谨地对待这个问题,我们可以加入一些检查代码,确保不选中同一个对象;但是这么做并不会带来很大的效益
- 得到双亲后,下面我们就开始执行交叉和突变过程。
DNA child = parentA.crossover(parentB); 交叉函数 A
child.mutate(); 突变函数
- 当然,crossover()函数和mutate()函数需要我们自己来实现。从上面的调用方式可以看出,crossover()函数的参数是DNA对象,它的返回值是一个新的DNA对象,也就是子代个体。
DNA crossover(DNA partner) { 函数的参数是DNA对象,返回值也是DNA对象
DNA child = new DNA(); 子代是新的DNA对象,DNA在构造函数中是用随机方式初始化的,但我们会
int midpoint = int(random(genes.length)); 在基因数组中选择随机的“中间点
for(int i = 0; i < genes.length; i++) {
if (i > midpoint) child.genes[i] = genes[i]; 中间点之前和之后的基因来自不同的父
else child.genes[i] = partner.genes[i];
}
return child; 返回子代DNA
}
- 上述crossover()函数的实现使用了“随机中间点”方法,子代基因的第一部分取自parentA,第二部分取自parentB。
- mutate()函数比crossover()函数更容易实现。我们只需要遍历基因数组,根据突变率为每个字符随机选择一个新字符。举个例子,如果突变率为1%,我们将有1%的概率选择一个新字符。
float mutationRate = 0.01;
void mutate() {
for (int i = 0; i < genes.length; i++) { 遍历数组中的每个基因
if(random(1) < mutationRate) {这里的代码有1%的机会执行
genes[i] = (char) random(32,128); 突变,产生随机字符
}
}
}