【数模/启发式算法】遗传算法

简介

 遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。

符号说明

符号含义
n n n种群个体个数
a a a求解区间左端点
b b b求解区间右端点
l e n g t h length length编码长度
X X X编码串的二进制转十进制值
v a l val val编码串的映射值
p c pc pc‘基因’交叉的概率
p m pm pm‘基因’变异的概率

核心思想

 遗传算法借鉴了达尔文的进化论和孟德尔的遗传学说。其本质是一种并行、高效、全局搜索的方法。其能够在搜索过程中自动获取和积累搜索空间的知识,并自适应的控制搜索过程以获得最优解。

 遗传算法使用“适者生存”的原则,在潜在的解决方案种群中逐次产生一个近似最优的方案。在遗传算法的每一代中,根据个体在问题域中的适应度和从自然学说中借鉴来的再造方法进行个体选择,产生一个新的近似解。在这个过程中导致种群的进化,得到的新个体比原个体更能适应环境,就像自然界中的改造一样。

流程图

在这里插入图片描述

文章使用到的测试函数

一元函数: y = − a b s ( x s i n ( x ) c o s ( 2 x ) − 2 x s i n ( 3 x ) + 3 x s i n ( 4 x ) ) ,     x ∈ [ 0 , 50 ] y = -abs(xsin(x)cos(2x)-2xsin(3x)+3xsin(4x)), \ \ \ x \in [0, 50] y=abs(xsin(x)cos(2x)2xsin(3x)+3xsin(4x)),   x[0,50]参考最小值为: m i n ( y ) = − 219.501 min(y) = -219.501 min(y)=219.501
在这里插入图片描述

二元函数: y = x 1 2 + x 2 2 − x 1 x 2 − 10 x 1 − 4 x 2 + 60 y = x_{1}^{2}+x_{2}^{2}-x_{1}x_{2}-10x_{1}-4x_{2}+60 y=x12+x22x1x210x14x2+60参考最小值为: m i n ( y ) = 8.0 min(y) = 8.0 min(y)=8.0
在这里插入图片描述

遗传算法基本原理

编码解码

常见的编码方式为使用二进制进行编码,并利用解码函数将二进制码映射到可行域中。对于不同的问题编码方式会作出相应调整。

当串长 l e n g t h = n length=n length=n,可行域为 [ a , b ] [a, b] [a,b]时。我们将可行域划分为 2 n − 1 2^{n}-1 2n1份,其中一个二进制串s(s的10进制值 ∈ [ 0 , 2 l e n g t h − 1 ] \in [0, 2^{length}-1] [0,2length1])所映射值的计算公式为: v a l = a + X ∗ b − a 2 l e n g t h − 1 val = a + X*\frac{b - a}{2^{length} - 1} val=a+X2length1ba其中, X X X表示s的十进制值。能够直观理解,将原区间划分为 2 l e n g t h − 1 2^{length} - 1 2length1份,每一份的值为 b − a 2 l e n g t h − 1 \frac{b - a}{2^{length} - 1} 2length1ba

因此,串长决定了每个二进制串映射值的精度,串长越长则划分越细精度越高。(注意:每个串表示的精度越高,也间接影响到遗传算法计算结果的精度。通常串长取20-30较为合适。)

代码中的二进制映射函数:

# 二进制 ”转“(映射)十进制
# 公式:val = 区间begin + 串十进制值 * 区间长度 / (2^length - 1)
# 注意:为适应多元函数,返回值为一个包含var个实数值的向量
def m_decode(self, indiv):
    xpos = [0] * self.var
    # var个自变量
    for i in range(self.var):
        xpos[i] = self.lb[i] + int(indiv[i], 2) * (self.ub[i] - self.lb[i]) / (2 ** self.length - 1)

    return xpos
“基因”复制

在这里插入图片描述
为了得到最优解,算法模拟基因编码的复制。并控制较为优秀的基因要多复制(表现为复制概率更大),而较差一点的基因要少复制(表现为复制概率较小)。这里的优秀与否取决于对应编码的适应度。

那么,如何根据适应度来赋予复制概率,并按照概率来进行复制呢?

假设,我们在解决一个函数最大值的问题。此时适应度即为编码对应的函数值,假设fit(a) = 1,fit(b) = 2,fit(c ) = 3,fit(d) = 4。对每个编码适应度进行归一化,即可得到对应的概率P为:P(a) = 1/10, P(b) = 2/10, P(c ) = 3/10, P(d) = 4/10。

有了编码对应的概率,我们要如何依概率进行复制呢?
我们将概率进行一次累加得到[1/10, 3/10, 6/10, 10/10],此时我们取一随机数,若随机数落入区间为 r ≤ 1 / 10 r \le 1/10 r1/10则编码1需要复制、随机数落入区间为 1 / 10 < r ≤ 3 / 10 1/10< r \le 3/10 1/10<r3/10则编码2需要复制…

我们只需要得到一组随机数,并将其排序依次对累加概率进行比较,即可按概率进行复制。此方法相当于将区间问题转化为右端点问题,简化了原问题。

基因复制代码(预处理部分为了保证函数值越小,概率越大):

# 基因(编码)复制
def m_copy(self):
    new_popu = [[''] * self.var for _ in range(self.n)]
    # 计算复制每个个体复制基因的概率, 概率越大复制概率越大
    ## 按照取值赋概率, 取值越小概率越大。 因此对所有取值先预处理
    ### 预处理:首先要非负,因为概率取值原理是归一化

    minval = min(self.fit)
    addval = 0
    if minval <= 0:
        # 原值要加上addval, 保证取倒数后分母不能为0。 取倒数原因:值越小需要概率越大
        addval = -minval + 1

    tem = list(map(lambda x : 1 / (x + addval), self.fit))
    s_tem = sum(tem)
    # 归一化计算概率
    p = list(map(lambda x : x / s_tem, tem))

    # 概率求累加, 为了方便让概率大的多复制
    cum_p = [0] * self.n
    cum_p[0] = p[0]
    for i in range(1, self.n):
        cum_p[i] = cum_p[i - 1] + p[i]

    # 制造一组有序的随机数, 随机数落入累加区间即需要复制
    choice = [random.random() for _ in range(self.n)]
    choice.sort()

    i = 0
    j = 0
    while j < self.n and i < self.n:
        # 只要当前随机数小于右端点就说明落入该区间,需要复制
        if choice[j] <= cum_p[i]:
            new_popu[j] = deepcopy(self.popu[i])
            j = j + 1
        else: # 随机数大于右端点,需要和之后的区间进行比较
            i = i + 1

    return new_popu
“基因”交叉

在这里插入图片描述
使用三段式交叉方式,即掐头,去尾,交换中间(可以参考上图)。
代码中对相邻两编码进行“基因”交叉操作,所交换部分由随机数控制。

基因交叉代码:

# 基因(编码)交叉
def m_cross(self, new_popu):
    # 相邻两个个体同种基因(同一自变量编码)进行交叉
    i = 1
    while i < self.n:
        if random.random() < self.pc:
            # 取出要进行交叉的两个个体
            indiv1 = deepcopy(new_popu[i - 1])
            indiv2 = deepcopy(new_popu[i])

            # 逐变量进行编码交叉
            # hmax 划分值:self.length - 1, 因为下边从1开始
            hmax = self.length - 1
            for j in range(self.var):
                h1 = random.randint(0, hmax)
                h2 = random.randint(0, hmax)

                if h1 > h2:
                    h1, h2 = h2, h1

                # 交叉划分构成的区间
                new_popu[i - 1][j] = indiv1[j][0 : h1] + indiv2[j][h1 : h2 + 1] + indiv1[j][h2 + 1:]
                new_popu[i][j] = indiv2[j][0 : h1] + indiv1[j][h1 : h2 + 1] + indiv2[j][h2 + 1:]

        i = i + 2

    return new_popu
“基因”变异

在这里插入图片描述
由于采用二进制编码,因此“基因”变异十分简单,可以描述为:随机选择位点进行取反操作即可,因为二进制串只有0和1。

“基因”变异代码:

# 基因(编码)变异
def m_mutation(self, new_popu):
    # n个个体
    for i in range(self.n): # var个自变量
        for j in range(self.var):
            if random.random() < self.pm:
                # 随机挑选2个数变异
                for k in range(2):
                    # 要变异的下标
                    idx = random.randint(0, self.length - 1)
                    if new_popu[i][j][idx] == '0':
                        new_popu[i][j] = new_popu[i][j][0:idx] + '1' + new_popu[i][j][idx + 1:]
                    else:
                        new_popu[i][j] = new_popu[i][j][0:idx] + '0' + new_popu[i][j][idx + 1:]

    return new_popu

遗传算法代码

Python版本:


import random
from copy import deepcopy
import math

def func(x):
    # 一元函数测试
    return -abs(x[0] * math.sin(x[0]) * math.cos(2 * x[0]) - 2 * x[0] * math.sin(3 * x[0]) + 3 * x[0] * math.sin(4 * x[0]))

    # # 二元函数测试
    # return x[0]**2 + x[1]**2 - x[0]*x[1] - 10 * x[0] - 4 * x[1] + 60

class GA:

    def __init__(self, func, n, var = 1, length = 20, iter = 50, lb = None, ub = None):
        """ 默认寻找最小值,以及对应自变量取值。 若需要寻找最大值,对目标函数乘-1,并对最终结果乘-1即可
        Args:
            :param func: type: 函数, des: 所要求解优化问题的目标函数
            :param n: type: int, des: 粒子群粒子的个数
            :param var: type: int, des: 函数中自变量的个数,即:几元函数
            :param length: type: int, des: 用于编码的串长了。
            :param iter: type: int, des: 迭代次数
            :param lb: type: list(double), des: 每一种自变量的下界,注意应和自变量一一对应
            :param ub: type: list(double), des: 每一种自变量的上界,注意应和自变量一一对应
        """
        if lb is None:
            lb = []
        if ub is None:
            ub = []

        # 目标函数
        self.func = func
        # 初始化种群个数
        self.n = n
        # 初始化编码串长
        self.length = length
        # 初始化变量种类数
        self.var = var
        # 初始化迭代次数
        self.iter = iter
        # 初始化自变量范围 len(lb) = len(ub) = var
        self.lb = lb
        self.ub = ub

        # 交叉概率和变异概率 0.6 - 0.1
        self.pc = 0.6
        self.pm = 0.1

        # 初始化适应度
        self.fit = [0] * n

        # 产生初始群体 每一行为一个种群个体的var个字符串, 因为每一个个体需要var个变量来描述
        ## var等于1时即为一元函数
        self.popu = [[''] * var for _ in range(n)]
        # 使用随机数初始个体
        for i in range(n): # n个个体
            for j in range(var): # 每个个体的自变量个数
                self.popu[i][j] = str(bin(random.randint(0, int(2 ** length))))[2:]
                if len(self.popu[i][j]) < length:
                    self.popu[i][j] = '0' * (length - len(self.popu[i][j])) + self.popu[i][j]

        # 最优解对应的对应自变量取值
        self.x = self.m_decode(self.popu[0])
        self.fit[0] = self.func(self.x)

        # 用初代值计算一组解
        for i in range(1, n):
            now_x = self.m_decode(self.popu[i])
            self.fit[i] = self.func(now_x)
            if self.fit[i] < self.func(self.x): # 以求解最小值的方式更新当前最优解
                self.x = deepcopy(now_x)



    # 二进制 ”转“(映射)十进制
    # 公式:val = 区间begin + 串十进制值 * 区间长度 / (2^length - 1)
    # 注意:为适应多元函数,返回值为一个包含var个实数值的向量
    def m_decode(self, indiv):
        xpos = [0] * self.var
        # var个自变量
        for i in range(self.var):
            xpos[i] = self.lb[i] + int(indiv[i], 2) * (self.ub[i] - self.lb[i]) / (2 ** self.length - 1)

        return xpos


    # 基因(编码)复制
    def m_copy(self):
        new_popu = [[''] * self.var for _ in range(self.n)]
        # 计算复制每个个体复制基因的概率, 概率越大复制概率越大
        ## 按照取值赋概率, 取值越小概率越大。 因此对所有取值先预处理
        ### 预处理:首先要非负,因为概率取值原理是归一化

        minval = min(self.fit)
        addval = 0
        if minval <= 0:
            # 原值要加上addval, 保证取倒数后分母不能为0。 取倒数原因:值越小需要概率越大
            addval = -minval + 1

        tem = list(map(lambda x : 1 / (x + addval), self.fit))
        s_tem = sum(tem)
        # 归一化计算概率
        p = list(map(lambda x : x / s_tem, tem))

        # 概率求累加, 为了方便让概率大的多复制
        cum_p = [0] * self.n
        cum_p[0] = p[0]
        for i in range(1, self.n):
            cum_p[i] = cum_p[i - 1] + p[i]

        # 制造一组有序的随机数, 随机数落入累加区间即需要复制
        choice = [random.random() for _ in range(self.n)]
        choice.sort()

        i = 0
        j = 0
        while j < self.n and i < self.n:
            # 只要当前随机数小于右端点就说明落入该区间,需要复制
            if choice[j] <= cum_p[i]:
                new_popu[j] = deepcopy(self.popu[i])
                j = j + 1
            else: # 随机数大于右端点,需要和之后的区间进行比较
                i = i + 1

        return new_popu


    # 基因(编码)交叉
    def m_cross(self, new_popu):
        # 相邻两个个体同种基因(同一自变量编码)进行交叉
        i = 1
        while i < self.n:
            if random.random() < self.pc:
                # 取出要进行交叉的两个个体
                indiv1 = deepcopy(new_popu[i - 1])
                indiv2 = deepcopy(new_popu[i])

                # 逐变量进行编码交叉
                # hmax 划分值:self.length - 1, 因为下边从1开始
                hmax = self.length - 1
                for j in range(self.var):
                    h1 = random.randint(0, hmax)
                    h2 = random.randint(0, hmax)

                    if h1 > h2:
                        h1, h2 = h2, h1

                    # 交叉划分构成的区间
                    new_popu[i - 1][j] = indiv1[j][0 : h1] + indiv2[j][h1 : h2 + 1] + indiv1[j][h2 + 1:]
                    new_popu[i][j] = indiv2[j][0 : h1] + indiv1[j][h1 : h2 + 1] + indiv2[j][h2 + 1:]

            i = i + 2

        return new_popu


    # 基因(编码)变异
    def m_mutation(self, new_popu):
        # n个个体
        for i in range(self.n): # var个自变量
            for j in range(self.var):
                if random.random() < self.pm:
                    # 随机挑选2个数变异
                    for k in range(2):
                        # 要变异的下标
                        idx = random.randint(0, self.length - 1)
                        if new_popu[i][j][idx] == '0':
                            new_popu[i][j] = new_popu[i][j][0:idx] + '1' + new_popu[i][j][idx + 1:]
                        else:
                            new_popu[i][j] = new_popu[i][j][0:idx] + '0' + new_popu[i][j][idx + 1:]

        return new_popu


    def run(self):
        for k in range(1, self.iter + 1):

            # 控制交叉概率线性递减 [0.6 - 0.2]
            self.pc = 0.6 - 0.4 * k / self.iter
            # 控制变异概率线性递减 [0.3 - 0.1]
            self.pm = 0.3 - 0.2 * k / self.iter

            # "基因"复制
            new_popu = self.m_copy()
            # "基因"交叉
            new_popu = self.m_cross(new_popu)
            # "基因"变异
            new_popu = self.m_mutation(new_popu)

            for i in range(self.n):

                new_fit = self.func(self.m_decode(new_popu[i]))
                if new_fit < self.fit[i]:
                    # 概率保留优秀基因,因为较差的基因也有可能更新出最优解
                    if random.random() < 0.5:
                        self.fit[i] = new_fit
                        self.popu[i] = deepcopy(new_popu[i])

                    self.x = self.m_decode(new_popu[i])

        print(f'最优解为:{self.func(self.x)}')
        print(f'最优解对应自变量取值为:{self.x}')



"""一元函数测试"""
ga = GA(func, 50, 1, 20, 100, [0], [50])


"""二元函数测试"""
# ga = GA(func, 50, 2, 20, 100, [-15, -15], [15, 15])

ga.run()

以一元函数测试为例,对应输出为(结果较为不错):

最优解为:-219.4965723300476
最优解对应自变量取值为:[47.55863910545264]
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
标题——作者——出处 基于蚁群优化算法递归神经网络的短期负荷预测 蚁群算法的小改进 基于蚁群算法的无人机任务规划 多态蚁群算法 MCM基板互连测试的单探针路径优化研究 改进的增强型蚁群算法 基于云型理论的蚁群算法改进研究 基于禁忌搜索与蚁群最优结合算法的配电网规划 自适应蚁群算法在序列比对中的应用 基于蚁群算法的QoS多播路由优化算法 多目标优化问题的蚁群算法研究 多线程蚁群算法及其在最短路问题上的应用研究 改进的蚁群算法在2D HP型中的应用 制造系统通用作业计划与蚁群算法优化 基于混合行为蚁群算法的研究 火力优化分配问题的小生境遗传蚂蚁算法 基于蚁群算法的对等网拟器的设计与实现 基于粗粒度型的蚁群优化并行算法 动态跃迁转移蚁群算法 基于人工免疫算法和蚁群算法求解旅行商问题 基于信息素异步更新的蚁群算法 用于连续函数优化的蚁群算法 求解复杂多阶段决策问题的动态窗口蚁群优化算法 蚁群算法在铸造生产配料优化中的应用 多阶段输电网络最优规划的并行蚁群算法 求解旅行商问题的混合粒子群优化算法 微粒群优化算法研究现状及其进展 随机摄动蚁群算法的收敛性及其数值特性分析 广义蚁群与粒子群结合算法在电力系统经济负荷分配中的应用 改进的蚁群算法及其在TSP中的应用研究 蚁群算法的全局收敛性研究及改进 房地产开发项目投资组合优化的改进蚁群算法 一种改进的蚁群算法用于灰色约束非线性规划问题求解 一种自适应蚁群算法及其仿真研究 一种动态自适应蚁群算法 蚂蚁群落优化算法在蛋白质折叠二维亲-疏水格点型中的应用 用改进蚁群算法求解函数优化问题 连续优化问题的蚁群算法研究进展 蚁群算法概述 Ant colony system algorithm for the optimization of beer fermentation control 蚁群算法在K—TSP问题中的应用 Parallel ant colony algorithm and its application in the capacitated lot sizing problem for an agile supply chain 基于遗传蚁群算法的机器人全局路径规划研究 改进的蚁群算法在矿山物流配送路径优化中的研究 基于蚁群算法的配电网络综合优化方法 基于蚁群算法的分类规则挖掘算法 蚁群算法在连续性空间优化问题中的应用 蚁群算法在矿井通风系统优化设计中的应用 基于蚁群算法的液压土锚钻机动力头优化设计 改进蚁群算法设计拉式膜片弹簧 计算机科学技术 基本蚁群算法及其改进 TSP改进算法及在PCB数控加工刀具轨迹中的应用 可靠性优化的蚁群算法 对一类带聚类特征TSP问题的蚁群算法求解 蚁群算法理论及应用研究的进展 基于二进制编码的蚁群优化算法及其收敛性分析 蚁群算法的理论及其应用 基于蚁群行为仿真的影像纹理分类 启发式蚁群算法及其在高填石路堤稳定性分析中的应用 蚁群算法的研究现状 一种快速全局优化的改进蚁群算法及仿真 聚类问题的蚁群算法 蚁群最优化——型、算法及应用综述 基于信息熵的改进蚁群算法及其应用 机载公共设备综合管理系统任务分配算法研究 基于改进蚁群算法的飞机低空突防航路规划 利用信息量留存的蚁群遗传算法 An Improved Heuristic Ant-Clustering Algorithm 改进型蚁群算法在内燃机径向滑动轴承优化设计中的应用 基于蚁群算法的PID参数优化 基于蚁群算法的复杂系统多故障状态的决策 蚁群算法在数据挖掘中的应用研究 基于蚁群算法的基因联接学习遗传算法 基于细粒度型的并行蚁群优化算法 Binary-Coding-Based Ant Colony Optimization and Its Convergence 运载火箭控制系统漏电故障诊断研究 混沌扰动启发式蚁群算法及其在边坡非圆弧临界滑动面搜索中的应用 蚁群算法原理的仿真研究 Hopfield neural network based on ant system 蚁群算法及其实现方法研究 分层实体制造激光头切割路径的建与优化 配送网络规划蚁群算法 基于蚁群算法的城域交通控制实时滚动优化 基于蚁群算法的复合形法及其在边坡稳定分析中的应用 Ant Colony Algorithm for Solving QoS Routing Problem 多产品间歇过程调度问题的建与优化 基于蚁群算法的两地之间的最佳路径选择 蚁群算法求解问题时易产生的误区及对策 用双向收敛蚁群算法解作业车间调度问题 物流配送路径安排问题的混合蚁群算法 求解TSP问题的式学习并行蚁群算法 基于蚁群算法的三维空间机器人路径规划 蚁群优化算法及其应用 蚁群算法不确定性分析 一种求解TSP问题的相遇蚁群算法 基于蚁群优化算法的彩色图像颜色聚类的研究 钣金件数控激光切割割嘴路径的优化 基于蚁群算法的图像分割方法 一种基于蚁群算法的聚类组合方法 圆排列问题的蚁群拟退火算法 智能混合优化策略及其在流水作业调度中的应用 蚁群算法在QoS网络路由中的应用 一种改进的自适应路由算法 基于蚁群算法的煤炭运输优化方法 基于蚁群智能和支持向量机的人脸性别分类方法 蚁群算法在啤酒发酵控制优化中的应用 一种基于时延信息的多QoS快速自适应路由算法 蚁群算法中参数α、β、ρ设置的研究——以TSP问题为例 基于人工蚁群优化的矢量量化码书设计算法 具有自适应杂交特征的蚁群算法 蚁群算法在原料矿粉混匀优化中的应用 基于多Agent的蚁群算法在车间动态调度中的应用研究 用蚁群优化算法求解中国旅行商问题 蚁群算法在婴儿营养米粉配方中的应用 蚁群算法在机械优化设计中的应用 蚁群优化算法的研究现状及研究展望 蚁群优化算法及其应用研究进展 蚁群算法的理论与应用 简单蚁群算法的仿真分析 一种改进的蚁群算法求解最短路径问题 基于式求解旅行商问题的蚁群算法 一种求解TSP的混合型蚁群算法 基于MATLAB的改进型基本蚁群算法 动态蚁群算法求解TSP问题 用蚁群算法求解类TSP问题的研究 蚁群算法求解连续空间优化问题的一种方法 用混合型蚂蚁群算法求解TSP问题 求解复杂TSP问题的随机扰动蚁群算法 基于蚁群算法的中国旅行商问题满意解 蚁群算法的研究现状和应用及蚂蚁智能体的硬件实现 蚁群算法概述 蚁群算法的研究现状及其展望 基于蚁群算法的配电网网架优化规划方法 用于一般函数优化的蚁群算法 协同型与遗传算法的集成 基于蚁群最优的输电网络扩展规划 自适应蚁群算法 凸整数规划问题的混合蚁群算法 一种新的进化算法—蛟群算法 基于协同工作方式的一种蚁群布线系统

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sophon、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值