当阅读关于遗传算法的交叉部分时,书籍和论文通常指的是简单地交换要再现的两个所选候选者的数据中的比特的方法。
我还没有看到用于实际行业应用的实现遗传算法的实际代码,但我发现很难想象它足以在简单的数据类型上运行。
我一直想象遗传算法的各个阶段将在涉及复杂数学运算的复杂对象上执行,而不是仅仅在单个整数中交换一些位。
Even Wikipedia只列出了这些交叉操作。
我是否遗漏了一些重要的东西,或者这些交叉方法真的是唯一使用过的东西吗?
答案 0 :(得分:5)
使用了一些东西......虽然需要并行性和几代(有时是大量人口)导致使用表现良好的技术......
要记住的另一点是,在正确建模时“交换一些位”类似于自然发生的简单且相当准确的版本(基因重组,突变)......
对于一个非常简单且写得很好的演练,请参阅http://www.electricmonk.nl/log/2011/09/28/evolutionary-algorithm-evolving-hello-world/
有关更多信息,请参阅
答案 1 :(得分:3)
我一直想象遗传算法的各个阶段将在涉及复杂数学运算的复杂对象上执行,而不是仅仅在单个整数中交换一些位。
您可能认为使用了复杂的数学运算,因为您认为遗传算法必须修改复杂对象。这通常不是遗传算法的工作方式。
那么会发生什么?好吧,通常,程序员(或科学家)将在配置中识别各种参数,然后将这些参数映射到整数/浮点数。这确实限制了算法可以探索的方向,但这是获得任何结果的唯一现实方法。
让我们看一下天线的演变。您可以使用重新排列铜分子的遗传算法进行复杂的模拟,但这将是非常复杂的并且需要永远。相反,你会识别天线“参数”。大多数天线是由一定长度的导线构成的,在某些位置弯曲以最大化其覆盖区域。因此,您可以确定几个参数:起始线数,截面长度,弯曲角度。所有这些都很容易表示为整数,因此遗传算法很容易操作。由此产生的操作可以输入“天线模拟器”,以查看它接收信号的程度。
简而言之,当你说:
我发现很难想象只对简单的数据类型进行操作就足够了。
你必须意识到简单的数据类型可以映射到更复杂的结构。遗传算法不必了解这些复杂的结构。它需要知道的是它如何操纵构建复杂结构的参数。毕竟,DNA就是这样运作的方式。
答案 2 :(得分:1)
在遗传算法中,通常使用某些变量的位抖动。
正如你所说:
我一直想象遗传算法的各个阶段都会 在涉及复杂数学的复杂对象上执行 操作
我认为您正在寻找的是Genetic Programming,其中染色体描述了一个程序,在这种情况下,您可以在应用交叉时对操作员做更多的事情。
另外,请确保您已了解遗传算法中的适应度函数与遗传编程中染色体中的运算符之间的差异。
答案 3 :(得分:1)
不同的应用程序需要不同的encondigs。目标当然是找到最有效的编码,并且通常足够简单的编码更适合。因此,例如,作业车间调度问题可以表示为表示不同机器上的作业的执行顺序的排列列表(所谓的作业序列矩阵)。但是,它也可以表示为构建计划的优先级规则列表。旅行推销员问题或二次分配问题通常由单个排列表示,其表示一个案例中的旅行或另一个案例中的分配。优化仿真模型的参数或找到复杂数学函数的根通常由实数值向量表示。
对于所有这些,仍然存在简单类型的交叉和变异算子。对于排列,这些是例如OX,ERX,CX,PMX,UBX,OBX等等。如果您可以组合多个简单表示来表示复杂问题的解决方案,则可以重复使用这些操作并将它们单独应用于每个组件。
交叉有效运作的重要一点是应该满足一些属性:
您希望在交叉中避免所谓的不需要的突变。在这种情况下,你还希望避免在交叉之后修复大部分染色体,因为这也会引入不需要的突变。
如果您想尝试不同的操作符和问题,我们有一个很好的GUI驱动软件:HeuristicLab。
答案 4 :(得分:1)
简单的比特交换通常是要走的路。需要注意的关键是每个候选解决方案中使用的编码。应对解决方案进行编码,以便在新后代中引入最小或没有错误。任何错误都需要算法提供一个修复,这将导致处理时间的增加。
作为一个例子,我在C#中开发了一个大学时间表生成器,它使用整数编码来表示每天可用的时隙。此表示允许非常有效的单点或多点交叉运算符,它使用LINQ交叉函数来组合父项。
爬山的典型多点交叉
public List<TimeTable> CrossOver(List<TimeTable> parents) // Multipoint crossover
{
var baby1 = new TimeTable {Schedule = new List<string>(), Fitness = 0};
var baby2 = new TimeTable {Schedule = new List<string>(), Fitness = 0};
for (var gen = 0; gen < parents[0].Schedule.Count; gen++)
{
if (rnd.NextDouble() < (double) CrossOverProb)
{
baby2.Schedule.Add(parents[0].Schedule[gen]);
baby1.Schedule.Add(parents[1].Schedule[gen]);
}
else
{
baby1.Schedule.Add(parents[0].Schedule[gen]);
baby2.Schedule.Add(parents[1].Schedule[gen]);
}
}
CalculateFitness(ref baby1);
CalculateFitness(ref baby2);
// allow hill-climbing
parents.Add(baby1);
parents.Add(baby2);
return parents.OrderByDescending(i => i.Fitness).Take(2).ToList();
}