【问题标题】:Finding the least fit members in a genetic algorithm effeciently有效地在遗传算法中找到最不适合的成员
【发布时间】:2011-04-03 21:41:41
【问题描述】:

我已经在 java 中实现了一个遗传算法来解决我的一个班级的旅行商问题。它似乎工作得很好,但速度很慢。我代表一个人,我将其称为“Tour”的一个实例,它是一个代表旅行顺序的整数数组列表。 (即 [1,5,4,3,2,0] 表示按顺序前往城市 1,5,4,3,2,0,1。每一代都执行以下步骤...

  1. 按升序对总体进行排序(最合适的成员得分最低)
  2. 根据轮盘选择选择 20% 的种群进行繁殖,从而提高适应度较高的成员的繁殖机会
  3. 利用这 20% 来让 10% 的孩子使用贪婪交叉
  4. 随机贪婪变异 5% 的孩子
  5. 删除最低 10% 的人口并用子代替换(数组的前 90% 仍将在后面排序)
  6. 重复 50,000 次

我怀疑排序部分是瓶颈,因为我读过 Collections.sort 方法使用复制整个数组的 MergeSort。在我的情况下,这可能非常低效,因为当我想要的只是根据适应度进行排序时,它会复制一个数组或 Tours(它们本身就是数组)。除了排序之外,还有没有更好的方法来获得 Java 中最低 10% 的数组?或者可能是就地排序?感谢您的任何建议!

package assignment3;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Tsp {

private static int MAX_GENERATIONS = 50000;
private static int MUTATION_CHANCE = 5;

private Cities cityList;
private Population population = new Population();

public Tsp(Cities cityList) {
this.cityList = cityList;
this.population.createRandomPopulation(cityList);
}

public void clearTours() {
this.population.createRandomPopulation(cityList);
}

public Tour getBestTour() {
Collections.sort(this.population);
return this.population.get(0);
}

public void start() {
for (int generation = 0; generation < MAX_GENERATIONS; generation++) {
    Collections.sort(this.population);
    evolve();

}
}

private void evolve() {
// Sum all the fitnesses
// Update the breeding chance for each tour
// create a breeding array of ints that is 20% size of the population to
// be used to determine how to make the 10% children
// if array is odd add an index
// While the array size is too small
// loop through the population
// if array correct size exit loop
// compare random number with tour breeding chance
// make sure tour isn't in breeding array
// if pass random and not in breeding array
// add to breeding array
// end while

// loop through breeding array
// breed one parent with next
// store child in temp array

// For each child if randomly selected perform mutation

// remove 10% of worst children from population
// Add new children to population



ArrayList<Integer> breedingArray = getBreedingArray();
Population children = new Population();
for (int i = 0; i < breedingArray.size(); i += 2) {
    Tour parent1 = population.get(i);
    Tour parent2 = population.get(i + 1);
    children.add(parent1.performCrossover(cityList, parent2));
}

for (Tour t : children) {
    Random r = new Random();
    if (MUTATION_CHANCE >= r.nextInt(100)) {
    t.performGreedyMutation(cityList);
    }
}

int start = (population.size() - 1) - children.size();
int endIndex = population.size() - 1;

population.subList(start, endIndex).clear();
population.addAll(children);
}

private ArrayList<Integer> getBreedingArray( ) {
updateBreedingChance();

int breedingArraySize = (int) (this.population.size() * 0.2);
if (breedingArraySize % 2 != 0) {
    breedingArraySize += 1;
}

Random r = new Random();
ArrayList<Integer> breedingArray = new ArrayList<Integer>();
while (breedingArray.size() != breedingArraySize) {
    for (int i = 0; i < this.population.size(); i++) {
    if (breedingArray.size() == breedingArraySize) {
        break;
    }
    Tour check = this.population.get(i);
    boolean passesRandomSelection = r.nextDouble() < check.breadingChance;
    boolean notAlreadySelected = !breedingArray.contains(i);

    if (passesRandomSelection && notAlreadySelected) {
        breedingArray.add(i);
    }

    }
}
return breedingArray;
}

private void updateBreedingChance() {
double totalFitness = 0;
for (Tour t : this.population) {
    if (t.fitness == 0) {
    throw new RuntimeException("Fitness cannot be zero");
    }
    totalFitness += t.fitness;
}

double totalInverseFitness = 0;
for (Tour t : this.population) {
    totalInverseFitness += totalFitness / t.fitness;
}

for (Tour t : this.population) {
    t.breadingChance = (totalFitness / t.fitness) / totalInverseFitness;
}

}

}

【问题讨论】:

  • 老兄,这与遗传算法无关,这是关于java中的排序

标签: java sorting genetic-algorithm


【解决方案1】:

如果您“怀疑”某事是问题所在,那么您的第一个行动必须是找出问题是否存在。分析代码。然后你就会知道慢的位在哪里。您可以使用分析工具来执行此操作,或者只需在关键点调用 System.nanoTime() 并保留一些总数。在进行任何优化之前执行此操作!

现在,关于您正在排序的数组的一个有趣的事情是它通常是“大部分排序的”。其中前 90% 是上一轮的幸存者,他们被排序。您可以通过使用adaptive sort 来利用这一点,这对此类主要排序的数组所做的工作较少。有几种已知的自适应排序,但一个很好的通用类型是Timsort。这实际上将成为 Java 7 中的标准排序——关于它的 Wikipedia 文章的脚注包括一个指向将要使用的 OpenJDK 中代码的链接,您可以简单地窃取它。

比应用自适应排序更好的是首先对新孩子进行排序(使用自适应排序,因为您首先培育出最适合的父母,因此平均而言,最适合的孩子会首先出现),然后将它们合并到已经排序的父母列表中。您可以通过并行遍历父数组和子数组并在需要的地方插入子数组,在 O(n) 时间内直接合并它们。您可以在此处查看使用 LinkedList,否则您可能会在 System.arrayCopy() 中花费大量时间。

此外,在 getBreedingArray() 中,您说的是 breedingArray.contains(i) - 对于数组,这是一个 O(n) 操作。您可能应该在这里使用 LinkedHashSet 而不是数组。从头开始 - 使用 BitSet。

【讨论】:

  • 我做了一些粗略的分析,只是在调试过程中暂停应用程序,奇怪的是,getBreedingArray 函数似乎是它停止最多的函数。特别是创建随机数......不确定这是否重要。你的意思是 .contains 是一个“n”操作吗?我认为 O(1) 是你能做到的最好的复杂性。
  • 是的,我的意思是 O(n),抱歉!现已修复。
【解决方案2】:

在步骤 (5) 中进行部分排序可能会更快。简单算法:使人口为heap,然后从这个堆中弹出 0.1 * n 次。 (这是部分heapsort;更好的算法可在the literature 中获得,包括一种称为“quickselsort”的算法。)

【讨论】:

    猜你喜欢
    • 2014-12-25
    • 2018-03-08
    • 2010-11-07
    • 1970-01-01
    • 2017-05-30
    • 2018-05-06
    • 2017-10-03
    • 2015-07-21
    • 2011-10-11
    相关资源
    最近更新 更多