当染色体中基因的顺序很重要时,我们如何设计突变和交叉操作?

人工智能 遗传算法 交叉运营商 变异算子 约束优化 染色体
2021-11-17 11:32:57

考虑一个涉及一组任务的优化问题T={1,2,3,4,5},目标是找到这些任务的特定顺序。

我想用遗传算法解决这个问题,其中每个染色体C=[i,j,k,l,m]对应这五个任务的特定顺序,所以每个基因在C对应于一个任务T.

所以,例如,C=[1,3,5,4,2]C=[1,5,4,2,3]将是对应于两个不同任务顺序的两条染色体。

在这种情况下,我们如何设计变异和交叉操作,以便在进化过程中保持这些约束?

遗传算法应该产生三个最佳染色体或任务顺序。

2个回答

如果我理解正确,您的问题是关于使用遗传算法找到执行一系列任务以最大化结果的最佳方式。

简而言之,您正在尝试解决推销员问题。


如果我是正确的,您正在寻找允许您使用有序元素集的交叉和变异算法。对于这些场景,您通常会选择经典的 PMX(部分映射交叉)和交换突变。但是,还有很多其他的交叉算法可以使用 OX1、OX2(基于 Order Based Crossover 的两种变体)、Shuffle Crossover、Ring Crossover 等。让我们从变异开始,这样更容易。

为简单起见,我将有序基因组表示为整数数组:int[] genome = {1, 2, 3, 4, 5};

交换突变

这个概念非常基本:要突变一个有序的基因组,你只需交换两个元素。简单。

在此处输入图像描述

    public int[] InterchangeMutation(int[] genome)
    {
        int i1 = random.Next(0, genome.Length);
        int i2 = random.Next(0, genome.Length);

        var copy = genome.ToArray(); //just making a copy here
        copy[i1] = genome[i2];
        copy[i2] = genome[i1];

        return copy;
    }

PMX 变体交叉

这有点复杂,因为我们必须考虑重复。根据经验,我喜欢使用部分映射分频器的这种变体。它比原来的更容易实现(你可以在网上找到论文),但它会花费更多的计算复杂性。基因组越长,您付出的代价就越高。

  1. 首先选择两个父母用于交叉。
  2. 从第一个父 (P1) 中选择一个将被传递的随机部分。
  3. 对于剩余值:
    3A。如果它们不在复制部分,请从 P2
    3B 中获取。如果它们在复制部分,请从 P1
    3C 中取出。最终按照它们在 P1 中的顺序用缺失值填充空白

在此处输入图像描述

 public int[] PMX2Crossover(int[] P1, int[] P2)
    {
        //Initializing child genome
        int[] child = new int[P1.Length];
        for (int i = 0; i < P2.Length; i++) child[i] = -1;

        //Step1: getting random section to copy over
        int i1 = random.Next(0, P1.Length);
        int i2 = random.Next(0, P1.Length);

        //Step 2: Copying over section from P1
        for (int i = Math.Min(i1, i2); i < Math.Max(i1, i2); i++) child[i] = P1[i];

        //Step 3A: Copying values from P2
        for (int i = 0; i < P2.Length; i++) if (child[i] ==-1 && !child.Contains(P2[i])) child[i] = P2[i];

        //Step 3B: Copying values from P1
        for (int i = 0; i < P2.Length; i++) if (child[i] == -1 && !child.Contains(P1[i])) child[i] = P1[i];

        //Step 3C: Copying remaining values from P1
        int emptyGene = child.IndexOfFirst(-1);
        while (emptyGene != -1)
        {
            child[emptyGene] = FirstMissingGene(P1, child); 
            emptyGene = child.IndexOfFirst(-1);
        }

        return child;
    }

    private int FirstMissingGene(int[] parent, int[] child)
    {
        foreach (var gene in parent) if (!child.Contains(gene)) return gene;
        return -1; // should never get here
    }

您可以简单地使用跟踪已添加到子项的基因的哈希图将交叉的复杂性降低到 O(n)(从 O(n*n))。

要获得第一个孩子的电话PMX2Crossover(P1, P2);,第二个只需交换父母PMX2Crossover(P2, P1);

希望这对您有所帮助。

资料来源:我做过一段时间的人工智能学士教授。

您可以使用np.random.choiceshuffle 数组。您可以使用距离度量来查找作为当前良好集合的突变体的新数组。