当前位置:嗨网首页>书籍在线阅读

04-简单测试

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

5.3 简单测试

通用遗传算法 GeneticAlgorithm 适用于任何实现了 Chromosome 的类型。我们先来实现一个可以用传统方法轻松求解的简单问题作为测试,我们尽量让算式6x – x2 + 4y – y2的值最大化。换句话说就是,算式中的x和y取什么值会使该算式产生最大值?

利用微积分知识,分别对两个变量求偏导数并设为0,即可求得最大值。结果是x = 3且y = 2。本章中的遗传算法可以在不使用微积分的情况下得到相同的结果吗?下面将做深入的研究。具体代码如代码清单5-9所示。

代码清单5-9 simple_equation.py

from __future__ import annotations
from typing import Tuple, List
from chromosome import Chromosome
from genetic_algorithm import GeneticAlgorithm
from random import randrange, random
from copy import deepcopy
class SimpleEquation(Chromosome):
    def __init__(self, x: int, y: int) -> None:
        self.x: int = x
        self.y: int = y
    def fitness(self) -> float: # 6x - x^2 + 4y - y^2
        return 6 * self.x - self.x * self.x + 4 * self.y - self.y * self.y
    @classmethod
    def random_instance(cls) -> SimpleEquation:
        return SimpleEquation(randrange(100), randrange(100))
    def crossover(self, other:SimpleEquation) ->Tuple[SimpleEquation,SimpleEquation]:
        child1:SimpleEquation = deepcopy(self)
        child2:SimpleEquation = deepcopy(other)
        child1.y = other.y
        child2.y = self.y
        return child1, child2
    def mutate(self) -> None:
        if random() > 0.5: # mutate x
           if random() > 0.5:
               self.x += 1
           else:
               self.x -= 1
        else: # otherwise mutate y
           if random() > 0.5:
               self.y += 1
           else:
               self.y -= 1
    def __str__(self) -> str:
        return f"X: {self.x} Y: {self.y} Fitness: {self.fitness()}"

SimpleEquation 符合 Chromosome 的特征,正如其名,它的代码也尽量写得简单一些。 SimpleEquation 染色体中的基因可被视为 xy 两种。方法 fitness() 用算式6x−x2 + 4y−y2来对 xy 进行评分。根据 GeneticAlgorithm ,分值越大,个体的染色体适应度越高。在实例随机的情况下, xy 的初值设为0到100之间的随机整数,因此除用这两个值实例化新的 SimpleEquation 之外, random_instance() 不需要执行别的操作了。要在 crossover() 中让两个 SimpleEquation 结合,只需交换两个实例的 y 值即可创建两个后代。 mutate() 将随机增或减 x 值或 y 值。到此就足矣了。

因为 SimpleEquation 符合 Chromosome 的特征,所以现在我们已经可以将它放入 GeneticAlgorithm 中了。具体代码如代码清单5-10所示。

代码清单5-10 simple_equation.py(续)

if __name__ == "__main__":
   initial_population: List[SimpleEquation] = [SimpleEquation.random_instance() for _ in 
    range(20)]
    ga: GeneticAlgorithm[SimpleEquation] = GeneticAlgorithm(initial_population=initial_
    population, threshold=13.0, max_generations = 100, mutation_chance = 0.1, crossover_
    chance = 0.7)
   result:SimpleEquation = ga.run()
   print(result)

这里用到的参数是通过猜测检测(guess-and-check)得出的。不妨试试其他值。因为我们已经知道正确答案了,所以 threshold 被设为13.0。当x = 3且y = 2时,算式的值等于13。

如果事先不知道答案,那么或许要经过很多代才能找到最优解。这时可以将 threshold 设为任意数字。请记住,因为遗传算法是随机运行的,所以每次运行都会得到不同的结果。

下面是某次运行后的输出示例,遗传算法在第9代中求得了算式的解:

Generation 0 Best -349 Avg -6112.3
Generation 1 Best 4 Avg -1306.7
Generation 2 Best 9 Avg -288.25
Generation 3 Best 9 Avg -7.35
Generation 4 Best 12 Avg 7.25 
Generation 5 Best 12 Avg 8.5
Generation 6 Best 12 Avg 9.65
Generation 7 Best 12 Avg 11.7
Generation 8 Best 12 Avg 11.6
X: 3 Y: 2 Fitness: 13

如上所述,遗传算法得出了之前用微积分推导出来的正确解,即x = 3和y = 2,同时还列出了几乎每一代值,随着代数的增加,得出的解越来越接近正确解。

为了找到解,遗传算法要比其他方案消耗更多的计算资源,请充分考虑这一点。在现实世界中,以上这种简单的最大值问题不能充分发挥遗传算法的作用,但它的简单实现至少足以证明,遗传算法是有效的。