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

news/2024/4/26 12:54:31/文章来源:https://blog.csdn.net/qq_55799677/article/details/126323943

文章目录

      • 简介
      • 符号说明
      • 核心思想
      • 流程图
      • 文章使用到的测试函数
      • 遗传算法基本原理
        • 编码解码
        • “基因”复制
        • “基因”交叉
        • “基因”变异
      • 遗传算法代码

简介

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

符号说明

符号含义
nnn种群个体个数
aaa求解区间左端点
bbb求解区间右端点
lengthlengthlength编码长度
XXX编码串的二进制转十进制值
valvalval编码串的映射值
pcpcpc‘基因’交叉的概率
pmpmpm‘基因’变异的概率

核心思想

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

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

流程图

在这里插入图片描述

文章使用到的测试函数

一元函数:y=−abs(xsin(x)cos(2x)−2xsin(3x)+3xsin(4x)),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]参考最小值为:min(y)=−219.501min(y) = -219.501min(y)=219.501
在这里插入图片描述

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

遗传算法基本原理

编码解码

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

当串长length=nlength=nlength=n,可行域为[a,b][a, b][a,b]时。我们将可行域划分为2n−12^{n}-12n1份,其中一个二进制串s(s的10进制值∈[0,2length−1]\in [0, 2^{length}-1][0,2length1])所映射值的计算公式为:val=a+X∗b−a2length−1val = a + X*\frac{b - a}{2^{length} - 1} val=a+X2length1ba其中,XXX表示s的十进制值。能够直观理解,将原区间划分为2length−12^{length} - 12length1份,每一份的值为b−a2length−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/10r \le 1/10r1/10则编码1需要复制、随机数落入区间为1/10<r≤3/101/10< r \le 3/101/10<r3/10则编码2需要复制…

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

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

# 基因(编码)复制
def m_copy(self):new_popu = [[''] * self.var for _ in range(self.n)]# 计算复制每个个体复制基因的概率, 概率越大复制概率越大## 按照取值赋概率, 取值越小概率越大。 因此对所有取值先预处理### 预处理:首先要非负,因为概率取值原理是归一化minval = min(self.fit)addval = 0if minval <= 0:# 原值要加上addval, 保证取倒数后分母不能为0。 取倒数原因:值越小需要概率越大addval = -minval + 1tem = 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.ncum_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 = 0j = 0while j < self.n and i < self.n:# 只要当前随机数小于右端点就说明落入该区间,需要复制if choice[j] <= cum_p[i]:new_popu[j] = deepcopy(self.popu[i])j = j + 1else: # 随机数大于右端点,需要和之后的区间进行比较i = i + 1return new_popu

“基因”交叉

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

基因交叉代码:

# 基因(编码)交叉
def m_cross(self, new_popu):# 相邻两个个体同种基因(同一自变量编码)进行交叉i = 1while 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 - 1for 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 + 2return 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 mathdef 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] + 60class 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) = varself.lb = lbself.ub = ub# 交叉概率和变异概率 0.6 - 0.1self.pc = 0.6self.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 = 0if minval <= 0:# 原值要加上addval, 保证取倒数后分母不能为0。 取倒数原因:值越小需要概率越大addval = -minval + 1tem = 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.ncum_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 = 0j = 0while j < self.n and i < self.n:# 只要当前随机数小于右端点就说明落入该区间,需要复制if choice[j] <= cum_p[i]:new_popu[j] = deepcopy(self.popu[i])j = j + 1else: # 随机数大于右端点,需要和之后的区间进行比较i = i + 1return new_popu# 基因(编码)交叉def m_cross(self, new_popu):# 相邻两个个体同种基因(同一自变量编码)进行交叉i = 1while 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 - 1for 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 + 2return 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_popudef 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_fitself.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]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_20761.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux物理内存映射

文章目录前言一、物理内存映射1.1 x86_64虚拟地址空间简介1.2 kernel text mapping1.3 direct mapping of all phys memory二、__pa(x)函数和__va(x)函数2.1 direct mapping2.2 kernel text mapping三、API演示参考资料前言 实验平台&#xff1a; intel x86_64 centos 7&#…

基于订单系统的分库分表实战,让应用飞起来!

V-xin&#xff1a;ruyuanhadeng获得600页原创精品文章汇总PDF 前 言 各位读者朋友&#xff0c;大家好&#xff0c;这是分库分表实战的第一篇文章&#xff0c;首先介绍一下"基于ShardingSphere的分库分表实战"的设计思路及内容。 本实战的重点是分库分表实战&#x…

通讯录——文件读写版本

通讯录最终版本——文件读写 前面在暴躁小猿给大家分享了通讯录的静态版本和动态版本&#xff0c;但是这两个版本都不能实现文件的读写&#xff0c;每次运行程序都不能保存和读取数据&#xff0c;这样的通讯录是不完善的&#xff0c;根本没有办法去使用&#xff0c;所以为了满足…

Java毕设项目在线点餐系统计算机(附源码+系统+数据库+LW)

Java毕设项目在线点餐系统计算机&#xff08;附源码系统数据库LW&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

电源芯片的选择

什么是电源芯片?它有什么作用?在选择电源芯片的时候&#xff0c;应该考虑那些地方?输入电压线性调整率、输入电压线性变化时对输出电压的相对影响&#xff1f;下面先来了解几个概念问题&#xff1a; 1、输出电压负载调整率&#xff1a;负载电流变化时输出电压相对变化情况 …

(附源码)计算机毕业设计SSM在线考试主观题评分系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

神经网络适用于什么情况,神经网络是分类算法吗

1、人工神经网络评价法 人工神经元是人工神经网络的基本处理单元&#xff0c;而人工智能的一个重要组成部分又是人工神经网络。人工神经网络是模拟生物神经元系统的数学模型&#xff0c;接受信息主要是通过神经元来进行的。首先&#xff0c;人工神经元利用连接强度将产生的信号…

web响应式布局与BootStrap框架

目录什么是响应式网页布局媒体查询什么是媒体查询&#xff1f;媒体类型&#xff08;mediatype&#xff09;关键字媒体特性&#xff08;media feature&#xff09;引入方式BootStrap简介使用步骤栅格系统组件JavaScript插件定制案例腾讯前端web首页什么是响应式网页布局 响应式…

Excel工作日日历

在项目管理中&#xff0c;通常需要制作一个工作日历&#xff0c;能标识出休假日。 难点在识别休假日&#xff0c;不能简单根据周几来判断&#xff0c;而是要根据国家法定假日和换班日进行判断。我做了一个示例&#xff0c;给感兴趣的朋友演示一下。 我会分步骤讲解一下如何制作…

APS高级排产如何帮助帮助企业制定生产计划?

对于物料及产能规划与现场详细作业排程而言&#xff0c;企业常因无法确实掌握生产制造现场实际的产能状况及物料进货时程&#xff0c;而采取有单就接的接单政策与粗估产能的生产排程方式&#xff0c;但又在提高对顾客的服务水平及允诺交期的基本前提下&#xff0c;导致生产车间…

Redis配置文件详解

容量单位不区分大小写&#xff0c;G和GB有区别 可以使用 include 组合多个配置问题 网络配置 日志输出级别 日志输出文件 持久化规则 由于Redis是基于内存的数据库&#xff0c;需要将数据由内存持久化到文件中 持久化方式&#xff1a; RDBAOF RDB文件相关 主从复制 Security模…

【建立逻辑结构】

前言 这是【Windows Server 2016 服务器配置与管理】的一些实操 下面是我自己做实验过程当中的一些简单记录&#xff0c;可能会有小错误&#xff0c;欢迎大家的指正&#xff01; Slogan&#xff1a;日拱一卒&#xff0c;功不唐捐&#xff01;&#xff01;&#xff01; 问答题 …

【重识云原生】第四章云网络6.4.5.2节——Deployment配置详细说明

1 deployment配置说明 1.1 deployment的资源清单文件 主要字段说明&#xff1a; 全量字段说明&#xff1a; apiVersion: apps/v1 #版本号 kind: Deployment #类型 metadata: #元数据 name: #rs名称 namespace: #所属命名空间 labels: #标签 controller: deploy spec: #详…

Linux自动挂载 (autofs)

个人主页&#xff1a;&#x1f497;wei_shuo的个人主页 &#x1f3c0; Hello World &#xff01;&#x1f3c0; 文章目录实现自动挂载-autofsautofs工具简单使用autofs配置详细说明自动挂载资源有两种格式&#xff1a;相对路径挂载法绝对路径挂载法优化 Linux 系统性能安装 Tun…

动态代理详解

想要更加透彻的理解动态代理&#xff0c;首先要熟悉下静态代理 一、静态代理 总结来说&#xff1a;目标类和代理类实现了相同的接口&#xff0c;在代理类中依赖了目标类&#xff0c;代理类的方法中调用了目标类的方法&#xff0c;并做了一些增强性的工作。 1、实现静态代理&…

ROS|乌龟TF变换案例分析

1. 相关源码内容 1.1 turtle_df_demo.launch <launch><!-- Turtlesim Node--><node pkg"turtlesim" type"turtlesim_node" name"sim"/><node pkg"turtlesim" type"turtle_teleop_key" name"tel…

如何快速创建 GCDW 实例

GCDW 实例需云用户注册 GCDW 租户成功后&#xff0c; GBASE 云服务系统给租户分配独 立的实例&#xff0c; 同时创建租户的数据库根用户&#xff0c; 根用户即为该实例的超户&#xff0c; 拥有该实例 的最高权限&#xff0c; 租户可以通过根用户登录自己的实例管理数据&#xf…

Centos7 单机单网卡 RDO 安装 OpenStack

文档 OpenStack 涵盖太多知识量&#xff0c;总是找不到一个称心的官方文档 OpenStack Installation Guide for Red Hat Enterprise Linux and CentOS 这个是中文版的&#xff0c;但是 UPDATED: 2017-06-12 11:14 &#xff0c;很古老了&#xff01;基本概念和思想还是一样的 h…

SiO2/罗丹明B荧光杂化纳米微球/硅钼比核壳结构二氧化硅微球钼酸钙荧光粉的性能

SiO2/罗丹明B荧光杂化纳米微球性能制备&#xff1a; 在甲苯存在下的反相微乳液体系中,将γ-缩水甘油醚氧丙基三甲氧基硅烷(KH560)与罗丹明B进行预反应&#xff1b;再与正硅酸乙酯( TEOS)经原位溶胶-凝胶反应,制备SiO2/罗丹明B荧光杂化纳米微球.通过FTIR、UV-Vis、TEM、TG和光致…

聚焦 | 电力行业国产操作系统迎来大市场,麒麟信安积极承接发展新机遇

近年来&#xff0c;针对信息安全的外部环境不确定性加剧&#xff0c;作为关系到国计民生的电力行业&#xff0c;加速了自主创新的步伐。 从2009年起&#xff0c;电力行业就开始采用拥有自主核心技术的软硬件设施&#xff0c;到如今&#xff0c;整个电力行业已普遍完成了调度自动…