一、算法说明
基因算法
基因算法有一套公共的完整的框架,伪代码如下。
begin
set time t = 0 # first generation
initGeneration() # initialize the population P(t)
while the termination condition isnot met do
begin
fitness() # evaluate fitness of each member of the population P(t);
select() # select members from population P(t) based on fitness;
# produce the offspring of these pairs using genetic operators(cross,mutate);
# replace candidates of P(t), with these offspring;
cross() #
mutate() #
set time t = t + 1 # new generation
end
end
结合以上代码来分析一下基因算法:
- 第3行,首先要初始化第一代种群。这里涉及到一个个体是如何编码的,这一点对于不同的具体问题,要做出不同的实现。
- 第4~16行,在终止条件到来之前,种群一代代循环进化,具体如下:
- 第7行,计算种群个体的适应度,这里可以评估最优秀个体和平均适应度等。这一点上适应度对于不同的具体问题,其个体适应度计算方法不同,要做出不同实现。
- 第8行,根据个体的适应度不同,选出优秀的个体。这一点有多种不同的策略,例如轮盘赌策略和随机二选一的策略。
- 12~13行,选出优秀的个体之后,我们要用这些个体产生新一代的种群。具体方法则是交叉和变异。这里有两点需注意,一是交叉或变异的个体的选择有多种不同的策略,二是针对于不同的具体问题,交叉或变异的具体方法不同。
- 第15行,经过以上操作产生了新的一代,在这里做出标记。
- 当达到终止条件时,则结束进化。
代码设计
根据上述描述分析可以看出,基因算法有一套公用的框架。但有两点值得注意,一是选择,交叉,变异的个体选择有多种不同的策略;二是针对于不同的具体问题,个体的基因编码、交叉和变异的具体方式可能不同。所以在设计框架时,要为这两点留出余地,以便:1. 方便复用代码扩展新策略的基因算法,2. 复用代码实现针对于具体问题的基因算法。
设计图如下:
)
如设计图所示,GeneralGeneticAlgorithm已经实现了基因算法的基本框架,选择,交叉,变异的个体选择都有默认实现。
其默认的选择个体的策略时轮盘赌的策略。
默认的交叉是以一定概率挨个询问个体是否交叉,凑够两个时将两个个体进行交叉。
默认的变异是以一定概率挨个询问个体是否要变异。
其次使用该框架时,必须传入一个继承IGeneticAssistant接口的assistant,assistant决定个体的编码,交叉和变异方式。
使用如下:
IGeneticAssistant assistant = new BasicKnapSack(); //以背包问题为例
GeneralGeneticAlgorithm algorithm =
new GeneralGeneticAlgorithm(iterationMax, scale,
assistant, crossP, mutateP);//其他参数是迭代次数,种群规模,交叉概率,变异概率
algorithm.start(true); //调用此函数开始迭代,true表示迭代过程中打印出每代信息
// 结束后可以取出最好的个体
System.out.println(algorithm.getBestIndividual().toString());
然后也可以继承GeneralGeneticAlgorithm复用代码来实现新策略的基因算法,如图SequenceCross和RandomCross都是复写了父类cross算法,采用不通的策略来选择要交叉的个体。
背包问题
这时候解决背包问题就简单了,只要实现IGeneticAssistant决定个体的编码,适应度评估,交叉,变异和拷贝方式。如上设计图所示的BasicKnapsack类采用如下具体设计。
- 个体编码:用一个byte数组表示DNA,个体DNA的长度就是所有物品的数目,然后每一个位置的基因设置为0或1,表示不拿或拿当前的物品
- 适应度评估:评估方式很简单,就是将选择的个体的价值都加起来,作为适应度;但如果其总重量超过背包容量,就将其适应度置为0(为防止小概率的种群总适应度为0的情况,可以将此适应度置为接近0,如1e-10)
- 交叉:交叉方式是随机选一个起点和终点,然后将两个个体在起点和终点之间的基因段进行交换。
- 变异:变异方式是随机选一个起点和终点,然后将该个体在起点和终点之间的基因段中0变1,1变0
- 拷贝:由于编码采用数组,所以复制产生新个体时,要将数组中每个值都拷贝一份,才能避免使用相同地址空间。
然后设计图中RandomCrossMute复写交叉和变异的方法:
- 交叉:随机生成要改变基因数,然后挑选随机位置的基因进行互换。
- 变异:随机生成要改变基因数,然后挑选随机位置的基因0,1倒置。
设计图中的SequenceCrossMute顾名思义就是沿用了默认的方法,将其单独写出来,只是使得结构清新一点。
扩展其它策略的便签是指也可以继承BasicKnapsack来复写特定方法更改策略。
旅行商问题
旅行商问题也是要实现IGeneticAssistant决定个体的编码,评估,交叉,变异和拷贝方式。如上设计图所示的BasicTSP类采用如下具体设计(首先将所有地点存在一个数组里)。
个体编码:用一个int数组表示DNA,DNA是地点访问顺序的一个序列,也就地点数组下标的一个序列。
适应度评估:首先计算出旅行商按该个体DNA序列出发再回到起点的总路程,取其倒数作为适应度。也就是距离越短适应度越高
交叉:交叉的方式比教复杂,举个列子:
// 这是为交叉之前的两个DNA序列,先随机选取两个点将其分成三份。 p1 = ( 1 9 2 | 4 6 5 7 | 8 3 ) p2 = ( 4 5 9 | 1 8 7 6 | 2 3 ) // 然后将p2从第三部分开始得到临时的新序列tmp2 tmp2 = 2 3 4 5 9 1 8 7 6 // 这时候p1的三部分中的中间那部分(记为p12)保持不动, // 然后将第一部分和第三部分依此用tmp2中不在p12区间内的元素替换 // 然后就可以得到p1交叉后的结果c2 c1 = ( 2 3 9 | 4 6 5 7 | 1 8 ) // 同样,也可以得到p2交叉后的c2 c2 = ( 3 9 2 | 1 8 7 6 | 4 5 )
变异:变异比较简单,举个列子:
// 同样将待变异p1随机分成三部分 p1 = ( 1 9 2 | 4 6 5 7 | 8 3 ) // 然后将中间部分颠倒顺序就得到变异后的c1 c1 = ( 1 9 2 | 7 5 6 4 | 8 3 )
拷贝:由于编码采用数组,所以复制产生新个体时,要将数组中每个值都拷贝一份,才能避免使用相同地址空间。
最后扩展其它策略的便签是指也可以继承BasicTSP来复写特定方法更改策略,我没有实现其它策略。
二、背包问题实验分析
实验数据
输入:
30 50 // 30为背包容量,50为物体个数
7.1 2.6 // 物体重量 物体价值
3.4 5.9
8.2 3
2.3 1.9
0.1 6.6
8.8 8.5
1.2 9.4
5.7 0.8
1 0.3
6.8 4.4
0.5 0.5
3.3 0.1
3.7 4.1
6.9 8.2
9.8 7.6
2.4 0.1
2.6 1.2
8.3 8.1
1.6 7.3
2.6 3.2
1.8 7.4
4.3 5.4
5.2 6.2
7.1 4.1
2.2 1.9
6.5 1
6.8 6.5
0.8 5.3
4 5.6
4 5.3
2.4 7
7.2 6.6
1.6 5.8
3.4 2.2
1 7.2
1.9 3.3
2.8 9.6
1.3 8.8
3.4 6.8
9.8 4.5
2.9 4.4
3.1 6.1
7.9 7.8
3.3 7.8
6 0.6
7.4 6.6
4.4 1.1
5.6 5.9
5.4 8.3
1.7 4.8
实验设计
static double[] mutatePs = {
0.05,0.1,0.15,0.2,0.3,0.5,0.8};
static double[] crossPs = {
0.3,0.5,0.7,0.85};
static int[] scales = {
500,1000,1500};
for (int i = 0; i < crossPs.length; i++) {
for (int j = 0; j < mutatePs.length; j++) {
for (int j2 = 0; j2 < scales.length; j2++) {
doTrain(crossPs[i], mutatePs[j],
scales[j2], 10000);
}
}
}
实验设计就像如上代码所示,分别以一定的区间来跑完所有的测试,然后将每组测试输入的到对应的文件中。实验跑完之后,对实验结果进行分析,然后缩小区间再进行实验。
实验输出模式
实验过程中每隔300代输出一次,模式如下:
// 当前代数,当前代最佳适应度,当前代平均适应度,所有代中最佳适应度
g: 9901,best: 106.29999999999998,average: 82.61720000001445,best in total: 106.29999999999998
最终会输出最佳个体,以及最佳个体最早出现的代数
// 代数:适应度,个体编码
351:106.29999999999998,0 1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 0 1 0 1 0 0 0 0 0 1
实验结果分析
实验结果从以下角度来衡量
- 最佳个体适应度:参数优良性
- 最佳个体最早出现代数:收敛速度
- 最终几代最佳适应度和平均适应度:参数对种群特征的影响。
实验参数会从种群规模,交叉概率,变异概率,交叉变异算法来分析,实验结果见附件部分,具体分析如下
以下结果默认是随机选择交叉个体,具体的交叉变异方法是连续一段的交叉变异。
种群规模影响
实验序号 交叉概率 变异概率 种群规模 最佳最早出现代数 最佳个体适应度 最终代最高/平均适应度 1 0.3 0.05 1000 4985 101.39 96.599/91.689 2 0.3 0.05 1500 6039 104.69 102.99/98.249 3 0.3 0.05 500 7199 103.29 99.399/95.099 4 0.3 0.15 1000 5167 104.69 103.39/88.305 5 0.3 0.15 1500 2543 106.29 104.69/87.514 6 0.3 0.15 500 5384 106.29 104.79/85.406 16 0.3 0.5 1000 4934 106.29 101.69/56.033 17 0.3 0.5 1500 1759 106.29 102.49/55.495 18 0.3 0.5 500 5568 106.29 99.699/58.009 19 0.3 0.8 1000 8131 103.39 93.5/39.687 20 0.3 0.8 1500 2565 106.29 95.399/38.583 21 0.3 0.8 500 4590 102.89 88.099/39.505 从以上数据每三组对比分析,可得
- 种群规模较大的1500每次都取得最好的结果,而且除了第1、2、3组之外其它都是种群规模大的更快得到最优的个体。
- 但是种群规模大会导致训练速度变慢。
交叉变异概率的影响
实验序号 交叉概率 变异概率 种群规模 最佳最早出现代数 最佳个体适应度 最终代最高/平均适应度 1 0.3 0.05 1000 4985 101.39 96.599/91.689 2 0.3 0.05 1500 6039 104.69 102.99/98.249 3 0.3 0.05 500 7199 103.29 99.399/95.099 19 0.3 0.8 1000 8131 103.39 93.5,a/39.687 20 0.3 0.8 1500 2565 106.29 95.399/38.583 21 0.3 0.8 500 4590 102.89 88.099/39.505 22 0.5 0.05 1000 4222 106.29 103.99/98.414 23 0.5 0.05 1500 0 1.0E-1 1.0E-1/9.9999 24 0.5 0.05 500 0 1.0E-1 1.0E-1/1.0000 43 0.7 0.05 1000 0 1.0E-1 1.0E-1/9.9999 44 0.7 0.05 1500 0 1.0E-1 1.0E-1/9.9999 45 0.7 0.05 500 0 1.0E-1 1.0E-1/1.0000 73 0.85 0.2 1000 3235 106.29 106.29/82.733 74 0.85 0.2 1500 351 106.29 106.29/82.617 75 0.85 0.2 500 0 1.0E-1 1.0E-1/1.0000 76 0.85 0.3 1000 569 106.29 104.79/69.521 77 0.85 0.3 1500 386 106.29 104.59/71.282 78 0.85 0.3 500 6896 106.29 104.79/72.296 79 0.85 0.5 1000 2752 106.29 103.09/56.570 80 0.85 0.5 1500 340 106.29 101.89/56.360 81 0.85 0.5 500 6702 106.29 94.599/54.731 根据以上数据,可以看出交叉变异会严重影响种群,有以下几点
- 由于初始值是随机二选一,平均会选一半物品,导致一般一开始都会超过背包容积,这时,如果变异概率很小,会导致种群难以进化,根据上表,可以看到这一点再种群规模小,交叉概率大的时候更加显著。
- 交叉变异的概率增大,会使得种群的收敛速度变快,种群1500的基础上,上表74、77、80都是在500次以内收敛,而交叉变异概率小的3、20则收敛较慢。3和20内部对比,后者变异概率大,收敛也相对快许