我正在尝试使用Travelling Salesman Problem (TSP)来解决Genetic algorithm。我的基因组是图中顶点的排列(推销员的路径)。
我应该如何对基因组进行交叉操作?
在哪里可以找到C#中我的问题的实现?
答案 0 :(得分:12)
你应该检查Gokturk Ucoluk的“Genetic Algorithm Solution of the TSP Avoiding Special Crossover and Mutation”。它概述了排列的特殊交叉算子,并提出了一种巧妙的排列表示,它可以很好地与标准交叉相结合(即交叉两个排列总是产生两个排列)。
关键的洞察力是将排列表示为其反转序列,即对于每个元素i
,存储在a[i]
i
大于i
的元素位于{{1}的左侧1}}在排列中。与直接表示不同,a[i]
上的唯一约束是本地约束,即a[i]
不能大于N - i
。这意味着两个有效反演序列的简单交叉总是产生两个有效的反演序列 - 不需要对重复元素进行特殊处理。
答案 1 :(得分:7)
不是使用标准的GA交叉技术(如outlined by MusiGenesis),最好使用ordered cross-over for the Travelling Salesman problem。
通常的方法对于TSP来说效果不好,因为适应度函数对进化路线中不同城市的相对位置非常敏感,而不是它们的绝对位置。例如,如果您访问所有欧洲首都,最短的路线并不真正取决于您是否访问布拉迪斯拉发1日,2日或9日。更重要的是,你访问immediately before or immediately after visiting Vienna而不是访问赫尔辛基,雅典和其他6个首都。
当然,作为mjv also points out,传统的交叉也会在您的路线中引入重复。如果父母一方拥有位置2的巴黎而另一方拥有位于第14位的巴黎,则交叉可能会导致一条进化路线两次访问巴黎(并错过另一个城市),另一条进化路线根本不访问巴黎。有序的交叉遗传算子不会遇到这个问题。它保留元素并修改排序。
答案 2 :(得分:4)
以下是a C# program针对您所寻找的方法。
关于实施交叉的兴趣(或缺乏),这一切都取决于您的实现将使用的特定选择逻辑(和/或评估函数本身,例如,如果它包括对改进速度的评估)。在许多情况下,交叉操作将“从斩波块中拯救”一些在图形区域中有效/最佳但在某种程度上“卡在”其他区域的解决方案。这并不是说如果整体算法足够缓慢并且覆盖了解决方案空间的很大比例,则可能不会重新发现相同的解决方案,但交叉也可能会增加这些发现(和/或让您陷入困境)另一个当地最小值;-))
对于任何关注GA的人来说,没有直接相关但值得注意的是,由Alderman教授(RSA成名)在GA中进行的original "ultimate" experiment in GA原创“终极”实验,他使用了实际的DNA分子[进入C程序 - 开个玩意儿]来解决相关的图形问题,即哈密顿图的问题。
修改:在重新阅读问题时,我明白为什么要问这个问题,或者更准确地说为什么你会喜欢“不,你不想要交叉”的回复强> ;-)
您的 genonme与图表本身直接相关(没有任何错误,先验),但这会带来阻碍大多数交叉折叠不可行的障碍,因为他们可能有重复的节点(访问同一个城市两次或更多)并缺少节点(未能访问某些城市)...此外,可行的交叉将影响类似的图表,因此可能只是逐步扩大搜索,与什么突变会发现...
嗯...然后可能交叉,在这个特定的实现将无法帮助算法(并且确实需要大量的CPU来创建,测试和经常丢弃交叉后代,通过提供更多迭代和更慢的冷却速率来更好地使用CPU。除非!你找到了一种巧妙的执行交叉操作的方法; - )
答案 3 :(得分:3)
交叉的目的是通过将新的基因组组合在一起来扩展进化搜索空间。
进化过程所需的唯一真正标准是交叉的产物包含两个亲本的部分并代表有效的基因组。
只有您知道算法的有效性规则,因此只有您可以指定一个可行的交叉方法(除非您想要为您的基因组结构分享更多验证规则的详细信息)。
答案 4 :(得分:2)
以下是我在GA for TSP中所谓的“部分映射交叉”方法的确切实现。
Here是一篇论文,它在理论上解释了部分映射的交叉,下面是我的代码。
//construct a new individual with the genes of the parents
//method used is cross over mapping
//note that Individual datastrucuture contains an integer array called Genes which //contains the route.
//
public Individual Breed(Individual father, Individual mother)
{
int[] genes = new int[father.Genes.Length];
int[] map = new int[father.Genes.Length + 1]; //create a map to map the indices
int crossoverPoint1 = rand.Next(1, father.Genes.Length - 2); //select 2 crossoverpoints, without the first and last nodes, cuz they are always thje same
int crossoverPoint2 = rand.Next(1, father.Genes.Length - 2);
father.Genes.CopyTo(genes, 0); //give child all genes from the father
for (int i = 0; i < genes.Length; i++) //create the map
{
map[genes[i]] = i;
}
//int[] genesToCopy = new int[Math.Abs(crossoverPoint1 - crossoverPoint2)]; //allocate space for the mother genes to copy
if (crossoverPoint1 > crossoverPoint2) //if point 1 is bigger than point 2 swap them
{
int temp = crossoverPoint1;
crossoverPoint1 = crossoverPoint2;
crossoverPoint2 = temp;
}
//Console.WriteLine("copy mother genes into father genes from {0} to {1}", crossoverPoint1, crossoverPoint2);
for (int i = crossoverPoint1; i <= crossoverPoint2; i++) //from index one to the 2nd
{
int value = mother.Genes[i];
int t = genes[map[value]]; //swap the genes in the child
genes[map[value]] = genes[i];
genes[i] = t;
t = map[genes[map[value]]]; //swap the indices in the map
map[genes[map[value]]] = map[genes[i]];
map[genes[i]] = t;
}
Individual child = new Individual(genes);
return child;
}
答案 5 :(得分:1)
当我上大学的第一门课程时,我正在做一些关于各种GA运营商对解决方案融合的影响的计算(大约需要30页)。我记得,交叉不是TSP的最佳解决方案,更合适的解决方案是突变,它是顶点子序列的反转。
示例:
之前: BCDEF GH
之后: FEDCB GH
答案 6 :(得分:0)
AAAAAAAAAA
BBBBBBBBBB
重组这两个“父”序列的一种方法是随机选择一个交叉点(比如位置3),产生这两个“子”序列:
AAABBBBBBB
BBBAAAAAAA
或者,您可以随机选择两个交叉点(例如,3和8),从而产生以下两个序列:
AAABBBBBAA
BBBAAAAABB
为了有趣和额外的可变性,您还可以介绍偶尔发生点突变的可能性:
AAABBBABAA
BBBAAAAABB
关于如何在遗传算法中实现交叉,实际上并没有任何严格的规则,就像生物世界中没有任何关于进化论的硬性规则一样。无论什么有效,都有效。