在GA中执行与依赖关系交叉的好方法是什么?

时间:2015-01-14 21:28:51

标签: algorithm artificial-intelligence genetic-algorithm arithmetic-expressions

我正在编写一个遗传算法来查找表达目标数的表达式,即如果目标数是10,则解决方案将是2*5。现在我正在使用固定大小的染色体,我想将它改为随机长度,但只有在我找到一种方法来执行交叉之后。

以下是可能的染色体,遵守数字和运算符交替出现在字符串中的规则,其方式是没有两个数字或两个运算符相邻。合法字符串将以数字或+/-运算符开头。表达式将按原样从左到右计算(忽略算术运算的顺序):

  • 1/2+3+5
  • -2+4+1+8
  • -7+6*2+8
  • +2/5-1+8 2+1*2-2
  • +2*7*7+3
  • +1/2/2/6 5/5*9*1
  • +3-1+1*8 3-8+7*1

尝试实现交叉我尝试了以下(伪代码):

crossover(chrom-a, chrom-b):
    min_length = min(length(chrom-a), length(chrom-b))
    locus = random(1, min_length-1)

    while (chrom-a[locus] & chrom-b[locus] aren't both digit or operator)
        ocus = random(1, min_length-1)

    chrom-a = chrom-a[:locus] + chrom-b[locus:]
    chrom-b = chrom-b[:locus] + chrom-a[locus:]

    return chrom-a, chrom-b

但是功能没有按预期工作,有时需要花费太多时间才能找到合适的基因座。我必须找到一种方法使交叉工作与随机大小的染色体,但我无法弄清楚如何(当然,确保没有除零)。

1 个答案:

答案 0 :(得分:1)

长处理时间很可能是因为两个染色体在同一位置上具有不同类型(操作员或数字)的事件的概率很小。请注意,对于1位数字,两条染色体始终在同一位置具有相同的类型。解决方案是分别在每个染色体中找到分裂点:

find_loci(chrom-a, chrom-b):
    return pair(random(1, length(chrom-a)-1), random(1, length(chrom-b)-1))

crossover(chrom-a, chrom-b):
    locus-a, locus-b = find_loci(chrom-a, chrom-b)

while (chrom-a[locus-a] & chrom-b[locus-b] aren't both digit or operator)
    locus-a, locus-b = find_loci(chrom-a, chrom-b)

chrom-a = chrom-a[:locus-a] + chrom-b[locus-b:]
chrom-b = chrom-b[:locus-a] + chrom-a[:locus-b]
chrom-c = chrom-a[locus-a:] + chrom-b[locus-b:]
chrom-d = chrom-b[locus-a:] + chrom-a[:locus-b]

return chrom-a, chrom-b, chrom-c, chrom-d

结果当然是你有四个可能的结果,而不是两个。你可以使用全部,也可以忽略其中的一半。

另一个解决方法是首先枚举所有可能的分裂点:

enumerate_possible_loci(chrom-a, chrom-b):
    for all indexes i in (1, chrom-a):
        for all indexes j in (1, chrom-b):
            if type(chrom-a[i]) != type(chrom-b[j]):
                yield return pair(i, j)

crossover(chrom-a, chrom-b):
   possible_loci = enumerate_possible_loci(chrom-a, chrom-b)
   locus_pair = possible_loci[random(0, length(possible_loci) - 1)]

   locus-a = locus_pair[0]
   locus-b = locus_pair[1]

    chrom-a = chrom-a[:locus-a] + chrom-b[locus-b:]
    chrom-b = chrom-b[:locus-a] + chrom-a[:locus-b]
    chrom-c = chrom-a[locus-a:] + chrom-b[locus-b:]
    chrom-d = chrom-b[locus-a:] + chrom-a[:locus-b]

    return chrom-a, chrom-b, chrom-c, chrom-d

如果你总是只有1位数字,那么枚举可能的基因座的算法就更容易了,因为当一个索引是偶数而另一个索引是奇数时,它总会返回所有可能的对,反之亦然。