我想知道如何提高实现遗传算法的程序的整体效率,希望得到一些建议。是的,这是一个作业问题,但我已经独立完成了任务,只是想找到一种使其性能更好的方法。
问题描述
目前我的程序读取给定链,由“h”或“p”构成。(例如:hphpphhphpphphhpphph)对于每个H和P,它生成一个随机移动(上、下、左、右),并将该移动添加到包含在“染色体”对象中的ArrayList中。初始时,程序为10,000个染色体生成19个移动。
在此之后,需要从种群中选择染色体进行交叉。我的交叉函数从最适应的20%种群中随机选择第一个染色体,并从前20%以外的其它位置随机选择第二个染色体。然后对所选染色体进行交叉,并调用突变函数。我认为我最大的问题在于计算每个染色体的适应度。目前,我的适应度函数创建一个2D数组作为网格,按照上面显示的函数生成的移动列表的顺序放置移动,然后循环遍历数组进行适应度计算。(即,在位置[2,1]找到H,则Cord [1,1] [3,1] [2,0]或[2,2]也是H,如果找到H,则只增加发现的键数)。
计算完成后,将删除适应度最低的染色体并添加新染色体,然后对染色体数组列表进行排序。反复执行,直到找到目标解决方案。
如果您想看更多我的代码以证明我实际上已经完成了工作,请告诉我(不想发布太多,以免其他学生只是复制粘贴我的东西)。
SecureRandom sec = new SecureRandom();
byte[] sbuf = sec.generateSeed(8);
ByteBuffer bb = ByteBuffer.wrap(sbuf);
Random numberGen = new Random(bb.getLong());
int numberMoves = chromosoneData.length();
moveList = new ArrayList(numberMoves);
for (int a = 0; a < numberMoves; a++) {
int randomMove = numberGen.nextInt(4);
char typeChro = chromosoneData.charAt(a);
if (randomMove == 0) {
moveList.add(Move.Down);
} else if (randomMove == 1) {
moveList.add(Move.Up);
} else if (randomMove == 2) {
moveList.add(Move.Left);
} else if (randomMove == 3) {
moveList.add(Move.Right);
}
}
在此之后,需要从种群中选择染色体进行交叉。我的交叉函数从最适应的20%种群中随机选择第一个染色体,并从前20%以外的其它位置随机选择第二个染色体。然后对所选染色体进行交叉,并调用突变函数。我认为我最大的问题在于计算每个染色体的适应度。目前,我的适应度函数创建一个2D数组作为网格,按照上面显示的函数生成的移动列表的顺序放置移动,然后循环遍历数组进行适应度计算。(即,在位置[2,1]找到H,则Cord [1,1] [3,1] [2,0]或[2,2]也是H,如果找到H,则只增加发现的键数)。
计算完成后,将删除适应度最低的染色体并添加新染色体,然后对染色体数组列表进行排序。反复执行,直到找到目标解决方案。
如果您想看更多我的代码以证明我实际上已经完成了工作,请告诉我(不想发布太多,以免其他学生只是复制粘贴我的东西)。
根据评论建议,我在我的应用程序上运行了分析器(以前从未使用过,只是一年级计算机科学学生),我最初猜测的问题所在似乎有些不正确。从分析器告诉我的信息来看,主要的瓶颈在于:
- 将新染色体与种群中的其他染色体进行比较以确定其位置。我通过实现Comparable接口来完成这个操作:
public int compareTo(Chromosome other) {
if(this.fitness >= other.fitness)
return 1;
if(this.fitness ==other.fitness )
return 0;
else
return -1;
}
The other area of issue described is in my actual evolution function, consuming about 40% of the CPU time. A codesample from said method below
double topPercentile = highestValue; topPercentile = topPercentile * .20; topPercentile = Math.ceil(topPercentile); randomOne = numberGen.nextInt((int) topPercentile); //Lower Bount for random two so it comes from outside of top 20% int randomTwo = numberGen.nextInt(highestValue - (int) topPercentile); randomTwo = randomTwo + 25; //System.out.println("Selecting First: " + randomOne + " Selecting Second: " + randomTwo); Chromosome firstChrom = (Chromosome) populationList.get(randomOne); Chromosome secondChrom = (Chromosome) populationList.get(randomTwo); //System.out.println("Selected 2 Chromosones Crossing Over"); Chromosome resultantChromosome = firstChrom.crossOver(secondChrom); populationList.add(resultantChromosome); Collections.sort(populationList); populationList.remove(highestValue); Chromosome bestResult = (Chromosome) populationList.get(0);
The other main preformance hit is the inital population seeding which is performed by the first code sample in the post