【算法】遗传算法

遗传算法

    • 1 基本原理
    • 2 步骤
      • 2.1 编码
      • 2.2 复制
      • 2.3 交叉
      • 2.4 变异
    • 3 代码
    • 4 运行效果

1 基本原理

【算法】遗传算法_第1张图片
对每个个体都进行上述的进化,然后择优录取。

2 步骤

2.1 编码

二进制编码:用一个二进制串 表示 这个十进制数值 。

  • 给定数值解的区间范围: [ 1 , 10 ] [1,10] [1,10]
  • 给定精度: e − 5 e^{-5} e5 ,两个数值解的间隔。
  • 进行编码:为每个数值解 分配 一个独一无二的二进制串。
    【算法】遗传算法_第2张图片
    例如
    区间范围为 [ 1 , 10 ] [1, 10] [1,10],长度为 2 的串提供的精度为多少?对应精度为 10 − 1 2 2 − 1 = 3 \frac{10-1}{2^2 - 1} = 3 221101=3
    于是数值区间长度为 L ,精度为 E E E 的条件下,二进制串的长度 n ,三者关系为 L 2 n − 1 ≤ E \frac{L}{2^n - 1} ≤E 2n1LE
    要想达到 e − 5 e^{-5} e5的精度,对于 区间长度为 10 ,串的长度 n 应该满足 10 2 n − 1 ≤ 0.00001 \frac{10}{2^n - 1} ≤0.00001 2n1100.00001 n ≥ 20 n≥20 n20
    n = 20 n = 20 n=20 时, 串提供的精度约为 0.00000954
    例如
    [ 1 , 10 ] [1, 10] [1,10]为例,其十进制转换结果为 0 ∗ 2 0 + 1 ∗ 2 1 = 2 0*2^0 + 1 * 2^1 = 2 020+121=2
    对应表示的数值为: 7 = 1 + 2 ∗ 3 7 = 1 + 2 * 3 7=1+23
    [ 1 , 10 ] [1, 10] [1,10]为例,其十进制转换结果为 1 ∗ 2 0 + 1 ∗ 2 1 = 3 1*2^0 + 1 * 2^1 = 3 120+121=3
    对应表示的数值为: 10 = 1 + 3 ∗ 3 10 = 1 + 3 * 3 10=1+33
    一般的,区间范围为 [ a , b ] [a,b] [a,b],区间长度为 L ,即 L = b − a L = b - a L=ba串长为 n ,当前串对应十进制为 T ,则该串对应实值解为: X = a + T ∗ b − a 2 n − 1 X = a + T* \frac{b - a}{2^n - 1} X=a+T2n1ba
    X
    【算法】遗传算法_第3张图片

2.2 复制

个体进行复制,以概率进行基因的交叉,注意 复制交叉方式多种多样 。
复制

  • 将个体适应度大小映射为概率进行复制:适应度高的个体有更大概率复制,且复制的份数越多 轮盘赌法 。
  • 对适应度高的前 N 4 \frac{N}{4} 4N 的个体进行复制,然后用这些个体把后 N 4 \frac{N}{4} 4N个体替换掉 精英产生精英 。
  • 一定是将当前个体的复制体将下一个个体替换掉吗?随机可以吗? YES!
  • 一定只能把“坏解”替换掉吗?把随机某个适应度高的解替换掉呢? YES!

2.3 交叉

交叉

  • 按顺序,两两个体之间按概率交叉。如 1 和 2,2 和 3 等。或者 1 和 2,2 和 4 等,或者 1 和 4 这样。
  • 必须两两交叉? 3 个可以吗? YES! 。 5 个? YES!
  • 对适应度高的前 N 2 \frac{N}{2} 2N个体、甚至 N 4 \frac{N}{4} 4N 的个体之间相互交叉? YES!
  • 一定是按顺序交叉吗?对每个个体随机从前 N 2 \frac{N}{2} 2N 中选一个个体交叉? YES!
  • 一定是只有一段交叉?多段呢? YES!
    【算法】遗传算法_第4张图片

2.4 变异

变异

  • 每个个体都进行变异。
  • 只对适应度低的后 N 4 \frac{N}{4} 4N的,或者后 N 2 \frac{N}{2} 2N个个体变异? YES!
  • 必须都变异吗?按适应度大小映射为概率变异? YES!
  • 一定是只有一个位点变异?多个位点呢? YES!

【算法】遗传算法_第5张图片

轮盘赌基本思想:适应度越高的解,按道理越应该高概率的进行复制,且复制的份数应该越多。
对于个体 x i x_i xi,计算对应适应度 ( ) (_) f(xi) ==> = ( ) ∑ ( ) _ = \frac{(_)}{\sum{(_)}} pi=f(xi)f(xi)
【算法】遗传算法_第6张图片

3 代码

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation as animation  # 动画
import math

from numpy import random

# 解所在的可能区间
start = 0   # 起始
end = 8    # 结尾
# 迭代次数
iteration = 200
# 种群大小
size = 50
# 交叉概率
pc = 0.85
# 变异概率
pm = 0.05

# 表达式
def fitness(x):
    y = x * np.sin(4 * x) + 3 * x * np.cos(x) + 15
    return y

# 二进制编码
def getStrLen(precision):
    # 根据精度求串长
    l = math.ceil(math.log2((end - start) / precision + 1))
    return l

# 二进制解码: 二进制转十进制
def binaryDecode(matrix):
    len = getStrLen(1e-5)
    realValue = np.zeros(size)
    for i in range(size):  # 按照行来遍历
        for j in range(len):  # 对第i行进行遍历
            realValue[i] += matrix[i][j] * math.pow(2, j)

    for i in range(size):
        realValue[i] = start + realValue[i] * (end - start) / (math.pow(2, len) - 1)
    return realValue

# 复制
def copyX(parentX, fitness):  # martix 二进制基因片段;fitness种群的适应度
    l = getStrLen(1e-5)
    newX = np.random.randint(0, 2, (size, l))  #初始化一个下一代矩阵空间
    # print("初始化下一代矩阵")
    # print(newX)
    p = fitness / np.sum(fitness)  #概率
    cs = np.cumsum(p)  #累积概率
    # print("累积概率")
    # print(cs)
    cps= np.sort(np.random.rand(size))  # 轮盘赌,每个个体复制的概率
    # print("每个个体复制的概率")
    # print(cps)
    for i in range(size):
        if cps[i] < cs[i]:
            newX[i,:] = parentX[i,:]
    # print("复制后的种群")
    # print(newX)

    return newX


# 交叉方式 第i行的[crossStart, crossEnd]片段 与 第 i + 1行的[crossStart, crossEnd]片段交换
def crossX(matrix):
    i = 0
    l = getStrLen(1e-5)
    while i < size:
        if np.random.rand(1) < pc:
            positions = np.random.choice(l, 2, False)
            crossStart = positions.min()
            crossEnd = positions.max()
            np.random.choice(l, 2, False) # 在[0, len)之间选择两个不重复的数字
            j = (i + 1) % size
            pre = matrix[i: j, crossStart: crossEnd + 1]
            if j > i:
                matrix[i: j, crossStart: crossEnd + 1] = matrix[j: j + 1, crossStart: crossEnd + 1]
                matrix[j: j + 1, crossStart: crossEnd + 1] = pre
            i = i + 2
        else:
            i = i + 1

        if i >= size:
            break
    # print("交叉后的种群")
    # print(matrix)
    return matrix

# 变异
def mutationX(matrix):
    l = getStrLen(1e-5)
    for i in range(size):
        if np.random.rand(1) < pm:
            position = np.random.choice(l, 1, False)
            matrix[i][position] = np.mod((matrix[i][position] + 1), 2)

    # print("变异后的种群")
    # print(matrix)
    return matrix


if __name__ == '__main__':
    l = getStrLen(1e-5)
    # 生成初代种群,size--种群大小;len--串长
    matrix = np.random.randint(0, 2, (size, l))
    print("初代矩阵")
    print(matrix)
    # 绘制函数图像
    t = np.arange(start, end, 0.001)

    for i in range(iteration):
        dec = binaryDecode(matrix)  # 上一代解的十进制
        fit = fitness(dec)  # 上一代适应值
        # print("上代适应值")
        # print(fit)
        # print("*******  复制操作  ********")
        newX = copyX(matrix, fit)
        # print("*******  交叉操作  ********")
        newX = crossX(newX)
        # print("*******  变异操作  ********")
        newX = mutationX(newX)
        # 对下一代择优保留
        newDec = binaryDecode(newX)  #新一代十进制
        newFit = fitness(newDec) # 新一代适应度
        for j in range(size):
            if newFit[j] > fit[j]:
                matrix[j,:] = newX[j,:]    # 将好的子代替换进父代
        # 动态每一代最优值图像
        dec = binaryDecode(matrix)  # 择优后最终新一代解的十进制
        fit = fitness(dec)  # 择优后最终新一代适应值
        plt.plot(t, fitness(t), color='black')
        plt.scatter(dec, fit, s=5, c='red')
        plt.draw()
        plt.pause(0.2)
        plt.clf()


    dec = binaryDecode(matrix)  # 最终一代解的十进制
    fit = fitness(dec)  # 最一代适应值

    maxIndex = fit.argmax()

    plt.plot(t,fitness(t),color = 'black')
    plt.scatter(dec, fit, s=5, c='red')
    plt.scatter(dec[maxIndex], fit.max(), s=5, c = 'blue')
    plt.show()

# 取矩阵的第一行 matrix[0,:]
# 取矩阵的第一列 matrix[:,0]
# 取部分矩阵,行[i, j),列[m,n):matrix[i: j, m: n]
# 产生一个随机小数:np.random.rand(1)

# -------------------动态图-----------------------
# fig:窗口画布,用 fig, ax = plt.subplots() 生成
# func:要反复调用的函数(至少要传入一个参数),用该函数生成、更改图像
# frames:向要调用的函数传递的参数(默认依次传入0,1,2,3…)
# init_func:用于给定图像初始信息的函数

4 运行效果

你可能感兴趣的:(智能优化算法,python)