python实现GA求二元函数最大值(来自知乎)

原文连接:https://zhuanlan.zhihu.com/p/43546261python

下面讲述如何利用遗传算法解决一个二元函数的最大值求解问题。算法

问题app

二元函数以下: dom

# 画出图像以下
from mpl_toolkits.mplot3d import Axes3D import numpy as np from matplotlib import pyplot as plt fig = plt.figure(figsize=(10,6)) ax = Axes3D(fig) x = np.arange(-10, 10, 0.1) y = np.arange(-10, 10, 0.1) X, Y = np.meshgrid(x, y) Z = 0.5 - (np.sin(np.sqrt(X**2+Y**2))**2 - 0.5)/(1 + 0.001*(x**2 + y**2)**2) plt.xlabel('x') plt.ylabel('y') ax.set_zlim([-1,5]) ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow') plt.show()

 

 

咱们任务是找到 [公式] 范围以内的最大值。ide

 

创造染色体(编码)函数

咱们尝试为上文所述的函数 [公式] 的最大值所对应的 [公式] 和 [公式] 的值构造染色体。也就是说,要在一组二进制位中存储函数 [公式] 的定义域中的数值信息。编码

假如设定求解的精度为小数点后6位,能够将区间[-10,10]划分为 [公式] 个子区间。若用一组二进制位形式的染色体来表示这个数值集合, [公式] ,须要25位二进制数来表示这些解。换句话说,一个解的编码就是一个25位的二进制串。lua

如今,咱们已经建立了一种 25 位长度的二进制位类型的染色体,那么对于任意一个这样的染色体,咱们如何将其复原为[-10, 10]这个区间中的数值呢?这个很简单,只须要使用下面的公式便可:spa

[公式]

例如 0000 0000 0000 0000 0000 0000 0000 0 和 1111 1111 1111 1111 1111 1111 1 这两个二进制数,将其化为 10 进制数,代入上式,可得 -10.0 和 10.0。这意味着长度为 25 位的二进制数老是能够经过上式转化为[-10, 10]区间中的数。设计

 

个体、种群与进化

染色体表达了某种特征,这种特征的载体,能够称为“个体”。例如,我本人就是一个“个体”,我身上载有 23 对染色体,也许个人相貌、性别、性格等因素主要取决于它们。众多个体便构成“种群”。

对于所要解决的二元函数最大值求解问题,个体可采用上一节所构造的染色体表示,而且数量为2个,其含义可理解为函数f(x, y)定义域内的一个点的坐标。许多这样的个体便构成了一个种群,其含义为一个二维点集,包含于对角定点为(-10.0, -10.0)和(10.0, 10.0)的正方形区域。

也许有这样一个种群,它所包含的个体对应的函数值会比其余个体更接近于函数f(x, y)的理论最大值,可是它一开始的时候可能并不比其余个体优秀,它之因此优秀是由于它选择了不断的进化,每一次的进化都要尽可能保留种群中的优秀个体,淘汰掉不理想的个体,而且在优秀个体之间进行染色体交叉,有些个体还可能出现变异。种群的每一次进化后,一定会产生一个最优秀的个体。种群全部世代中的那个最优个体也许就是函数f(x, y)的最大值对应的定义域中的点。若是种群不休止的进化,它老是可以找到最好的解。可是,因为咱们的时间是有限的,有可能等不及种群的最优进化结果,一般是在获得了一个看上去还不错的解时,便终止了种群的进化。

那么,对于一个给定的种群,一般上述讲过的选择、交叉、变异来进行进化。

 

python实现

 

import math, random class Population: # 种群的设计
    def __init__(self, size, chrom_size, cp, mp, gen_max): # 种群信息合
        self.individuals = []          # 个体集合
        self.fitness = []              # 个体适应度集
        self.selector_probability = [] # 个体选择几率集合
        self.new_individuals = []      # 新一代个体集合
 self.elitist = {'chromosome':[0, 0], 'fitness':0, 'age':0} # 最佳个体的信息
 self.size = size # 种群所包含的个体数
        self.chromosome_size = chrom_size # 个体的染色体长度
        self.crossover_probability = cp   # 个体之间的交叉几率
        self.mutation_probability = mp    # 个体之间的变异几率
 self.generation_max = gen_max # 种群进化的最大世代数
        self.age = 0                  # 种群当前所处世代
          
        # 随机产生初始个体集,并将新一代个体、适应度、选择几率等集合以 0 值进行初始化
        v = 2 ** self.chromosome_size - 1
        for i in range(self.size): self.individuals.append([random.randint(0, v), random.randint(0, v)]) self.new_individuals.append([0, 0]) self.fitness.append(0) self.selector_probability.append(0) # 基于轮盘赌博机的选择
    def decode(self, interval, chromosome): '''将一个染色体 chromosome 映射为区间 interval 以内的数值''' d = interval[1] - interval[0] n = float (2 ** self.chromosome_size -1) return (interval[0] + chromosome * d / n) def fitness_func(self, chrom1, chrom2): '''适应度函数,能够根据个体的两个染色体计算出该个体的适应度''' interval = [-10.0, 10.0] (x, y) = (self.decode(interval, chrom1), self.decode(interval, chrom2)) n = lambda x, y: math.sin(math.sqrt(x*x + y*y)) ** 2 - 0.5 d = lambda x, y: (1 + 0.001 * (x*x + y*y)) ** 2 func = lambda x, y: 0.5 - n(x, y)/d(x, y) return func(x, y) def evaluate(self): '''用于评估种群中的个体集合 self.individuals 中各个个体的适应度''' sp = self.selector_probability for i in range (self.size): self.fitness[i] = self.fitness_func (self.individuals[i][0],   # 将计算结果保存在 self.fitness 列表中
                                                 self.individuals[i][1]) ft_sum = sum (self.fitness) for i in range (self.size): sp[i] = self.fitness[i] / float (ft_sum)   # 获得各个个体的生存几率
        for i in range (1, self.size): sp[i] = sp[i] + sp[i-1]   # 须要将个体的生存几率进行叠加,从而计算出各个个体的选择几率

    # 轮盘赌博机(选择)
    def select(self): (t, i) = (random.random(), 0) for p in self.selector_probability: if p > t: break i = i + 1
        return i # 交叉
    def cross(self, chrom1, chrom2): p = random.random()    # 随机几率
        n = 2 ** self.chromosome_size -1
        if chrom1 != chrom2 and p < self.crossover_probability: t = random.randint(1, self.chromosome_size - 1)   # 随机选择一点(单点交叉)
            mask = n << t    # << 左移运算符
            (r1, r2) = (chrom1 & mask, chrom2 & mask)   # & 按位与运算符:参与运算的两个值,若是两个相应位都为1,则该位的结果为1,不然为0
            mask = n >> (self.chromosome_size - t) (l1, l2) = (chrom1 & mask, chrom2 & mask) (chrom1, chrom2) = (r1 + l2, r2 + l1) return (chrom1, chrom2) # 变异
    def mutate(self, chrom): p = random.random () if p < self.mutation_probability: t = random.randint (1, self.chromosome_size) mask1 = 1 << (t - 1) mask2 = chrom & mask1 if mask2 > 0: chrom = chrom & (~mask2)  # ~ 按位取反运算符:对数据的每一个二进制位取反,即把1变为0,把0变为1 
            else: chrom = chrom ^ mask1   # ^ 按位异或运算符:当两对应的二进位相异时,结果为1 
        return chrom # 保留最佳个体
    def reproduct_elitist (self): # 与当前种群进行适应度比较,更新最佳个体
        j = -1
        for i in range (self.size): if self.elitist['fitness'] < self.fitness[i]: j = i self.elitist['fitness'] = self.fitness[i] if (j >= 0): self.elitist['chromosome'][0] = self.individuals[j][0] self.elitist['chromosome'][1] = self.individuals[j][1] self.elitist['age'] = self.age # 进化过程
    def evolve(self): indvs = self.individuals new_indvs = self.new_individuals # 计算适应度及选择几率
 self.evaluate() # 进化操做
        i = 0 while True: # 选择两个个体,进行交叉与变异,产生新的种群
            idv1 = self.select() idv2 = self.select() # 交叉
            (idv1_x, idv1_y) = (indvs[idv1][0], indvs[idv1][1]) (idv2_x, idv2_y) = (indvs[idv2][0], indvs[idv2][1]) (idv1_x, idv2_x) = self.cross(idv1_x, idv2_x) (idv1_y, idv2_y) = self.cross(idv1_y, idv2_y) # 变异
            (idv1_x, idv1_y) = (self.mutate(idv1_x), self.mutate(idv1_y)) (idv2_x, idv2_y) = (self.mutate(idv2_x), self.mutate(idv2_y)) (new_indvs[i][0], new_indvs[i][1]) = (idv1_x, idv1_y)  # 将计算结果保存于新的个体集合self.new_individuals中
            (new_indvs[i+1][0], new_indvs[i+1][1]) = (idv2_x, idv2_y) # 判断进化过程是否结束
            i = i + 2         # 循环self.size/2次,每次从self.individuals 中选出2个
            if i >= self.size: break
        
        # 最佳个体保留
        # 若是在选择以前保留当前最佳个体,最终能收敛到全局最优解。
 self.reproduct_elitist() # 更新换代:用种群进化生成的新个体集合 self.new_individuals 替换当前个体集合
        for i in range (self.size): self.individuals[i][0] = self.new_individuals[i][0] self.individuals[i][1] = self.new_individuals[i][1] def run(self): '''根据种群最大进化世代数设定了一个循环。 在循环过程当中,调用 evolve 函数进行种群进化计算,并输出种群的每一代的个体适应度最大值、平均值和最小值。'''
        for i in range (self.generation_max): self.evolve () print (i, max (self.fitness), sum (self.fitness)/self.size, min (self.fitness)) if __name__ == '__main__': # 种群的个体数量为 50,染色体长度为 25,交叉几率为 0.8,变异几率为 0.1,进化最大世代数为 150
    pop = Population (50, 24, 0.8, 0.1, 150) pop.run()

 

相关文章
相关标签/搜索