遗传算法是允许高度并行的算法,工程师通常使用Cuda实现遗传算法以应用到工程实际中,笔者在这里以Python语法实现,旨在能让更多的人理解遗传算法。
利用遗传算法求解如下最优化问题
m i n F = ∑ i = 1 3 W i g ( Q i ) min \ \ F = \sum_{i=1}^{3}W_{i}g(Q_{i}) min F=∑i=13Wig(Qi)
其中 g ( x ) = − 0.1544 × x 2 + 1.181 × x + 0.6028 g(x)=-0.1544\times x^{2}+1.181\times x+0.6028 g(x)=−0.1544×x2+1.181×x+0.6028
限制条件
Q e = ∑ i = 1 3 W i Q i Q_{e}=\sum_{i=1}^{3}W_{i}Q_{i} Qe=∑i=13WiQi
1.5 ≤ Q i ≤ 3.34 1.5\leq Q_{i} \leq 3.34 1.5≤Qi≤3.34
W i = 0 或 1 W_{i} = 0或1 Wi=0或1
实现遗传算法主要有这样几步,第一步,编码
为了满足精度的同时避免使用小数点,我们需要将自变量 Q i Q_{i} Qi乘以 10000 10000 10000;当然也可以采用其它设计方法,这里考虑到编程工具和计算机算力,设为此值。
Q i : ( 3.34 − 1.5 ) × 10000 = 18400 Q_{i}:(3.34-1.5)\times 10000 = 18400 Qi:(3.34−1.5)×10000=18400
2 14 ≤ 18400 ≤ 2 15 2^{14}\leq 18400 \leq 2^{15} 214≤18400≤215
故对 Q i Q_{i} Qi采用编码长度为15,对 W i W_{i} Wi采用编码长度为1
1.种群初始化
2.选择
3.繁殖
4.变异
5.是否满足循环次数:如果满足,则退出,否则,回到2
首先需要对种群进行初始化
#种群初始化
def groupinit(self):
for i in range(self.group_size):
self.group.append(individual())
for i in range(self.group_size):
#总基因长度:15*2+1*2,即基因的前30位代码Q1,Q2...
for j in range(32):
self.group[i].gene[j] = random.randint(0,1)
self.showgene()
#基因展示(将具有相应基因的个体,将基因性质表达出来)
def showgene(self):
for i in range(self.group_size):
temp = 0
for j in range(15):
temp|=self.group[i].gene[j]*2**j
self.group[i].Q[0] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
temp = 0
for j in range(15):
temp|=self.group[i].gene[j+15]*2**j
self.group[i].Q[1] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
#print(self.group[i].Q[0],self.group[i].Q[1])
self.group[i].W[0]=self.group[i].gene[30]
self.group[i].W[1]=self.group[i].gene[31]
_ = self.Qe -self.group[i].W[0]*self.group[i].Q[0]-self.group[i].W[1]*self.group[i].Q[1]
if _<1.5:
self.group[i].flag = False
self.group[i].fitness=0.0
elif _ >3.34:
self.group[i].flag = False
self.group[i].W[2] = 0
self.group[i].Q[2] = 0
self.group[i].fitness=0.0
else:
self.group[i].flag = True
self.group[i].W[2] = 1
self.group[i].Q[2] = _
_output = 0.0
for k in range(3):
_output+=self.group[i].W[k]*((-0.1544)*self.group[i].Q[k]*self.group[i].Q[k]+1.181*self.group[i].Q[k]+0.6028)
self.group[i].fitness =np.exp( -_output)
传统遗传算法的选择方式采用轮盘赌的方式将表现差的对象进行淘汰;但这里要解决问题的方式与传统的遗传算法解决的问题不一致。如果采用轮盘赌的方式,一些明明很接近有效值却因为不满足限制条件的个体则会被淘汰。这里仿照人类社会的方式进行选择。表现分最好的为国王,国王拥有绝对的存活率,表现分占前百分之十(不包括国王)的存活率是百分之九十,其它个体成为平民,平民拥有百分之七十的存活率。
#自然选择
def choose(self):
#排序,找到国王与贵族(设置第一位国王,贵族,贫民,国王不会被选择淘汰,贵族百分之90的生存率,贫民百分之60)
_noble = int(self.group_size/10)
#存在限制条件,更类似于人类社会
cmpfun = operator.attrgetter('fitness')#参数为排序依据的属性,可以有多个,这里优先id,使用时按需求改换参数即可
self.group.sort(key =cmpfun,reverse = True)
#for i in range(self.group_size):
# print(self.group[i].fitness)
new_group = []
new_group.append(self.group[0])
#贵族
for i in range(1,_noble):
_rand = random.random()
if(0.9>_rand):
new_group.append(self.group[i])
#平民
for i in range(_noble,self.group_size):
_rand = random.random()
if(0.6>_rand):
new_group.append(self.group[i])
self.group = new_group
我们设置了种群规模,在选择之后,部分个体被淘汰,这里通过繁衍的方式让种群规模恢复。先随机选择父本和木本,然后选取交换基因的结点
#繁衍(通过基因转换,构造新的种群)
def Propagate(self):
#繁衍第一步,随机选择父本和母本
_len_group = len(self.group)
_num = self.group_size - _len_group
for _i in range(_num):
#随机选择父本和母本
_father = random.randint(0,_len_group-1)
_mother = random.randint(0,_len_group-1)
_gp = random.randint(0,31)#选择基因交换位置
_ = individual()
_.gene = self.group[_father].gene[0:_gp]+self.group[_mother].gene[_gp:32]
self.group.append(_)
变异是遗传算法最为核心的内容,通过变异,引入了更多的基因型。
#进行变异
def mutation(self):
#国王不发生变异,其余个体按照变异率进行变异
for _i in range(1,self.group_size):
_rand = random.random()
if(self.mutationprop>_rand):
_gp = random.randint(0,31)#选择基因变异的位置
if(self.group[_i].gene[_gp]==1):
self.group[_i].gene[_gp] = 0
else:
self.group[_i].gene[_gp] = 1
'''
file: plugin.py
本文根据作者的想法构建了一个特殊的遗传类
除模拟遗传算法外,还模拟了简单的人类社会
'''
import numpy as np
import random
import operator
def g(x):
return np.float(-0.1544*x*x+1.181*x+0.6028)
class individual:
def __init__(self):
self.W = np.array([0.0,0.0,0.0],np.float)
self.Q = np.array([0.0,0.0,0.0],np.float)
self.gene =[0]*32
self.falg = False
self.fitness =0.0
class GA:
'''
para:
group_size 种群数量
Qe 限制条件中Qe的值
'''
def __init__(self,group_size,Qe,mutationprop):
self.group_size = group_size
self.group =[]
self.Qe = Qe
self.mutationprop = mutationprop
self.groupinit()
#种群初始化
def groupinit(self):
for i in range(self.group_size):
self.group.append(individual())
for i in range(self.group_size):
#总基因长度:15*2+1*2,即基因的前30位代码Q1,Q2...
for j in range(32):
self.group[i].gene[j] = random.randint(0,1)
self.showgene()
#基因展示(将具有相应基因的个体,将基因性质表达出来)
def showgene(self):
for i in range(self.group_size):
temp = 0
for j in range(15):
temp|=self.group[i].gene[j]*2**j
self.group[i].Q[0] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
temp = 0
for j in range(15):
temp|=self.group[i].gene[j+15]*2**j
self.group[i].Q[1] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
#print(self.group[i].Q[0],self.group[i].Q[1])
self.group[i].W[0]=self.group[i].gene[30]
self.group[i].W[1]=self.group[i].gene[31]
_ = self.Qe -self.group[i].W[0]*self.group[i].Q[0]-self.group[i].W[1]*self.group[i].Q[1]
if _<1.5:
self.group[i].flag = False
self.group[i].fitness=0.0
elif _ >3.34:
self.group[i].flag = False
self.group[i].W[2] = 0
self.group[i].Q[2] = 0
self.group[i].fitness=0.0
else:
self.group[i].flag = True
self.group[i].W[2] = 1
self.group[i].Q[2] = _
_output = 0.0
for k in range(3):
_output+=self.group[i].W[k]*((-0.1544)*self.group[i].Q[k]*self.group[i].Q[k]+1.181*self.group[i].Q[k]+0.6028)
self.group[i].fitness =np.exp( -_output)
#自然选择
def choose(self):
#排序,找到国王与贵族(设置第一位国王,贵族,贫民,国王不会被选择淘汰,贵族百分之90的生存率,贫民百分之60)
_noble = int(self.group_size/10)
#存在限制条件,更类似于人类社会
cmpfun = operator.attrgetter('fitness')#参数为排序依据的属性,可以有多个,这里优先id,使用时按需求改换参数即可
self.group.sort(key =cmpfun,reverse = True)
#for i in range(self.group_size):
# print(self.group[i].fitness)
new_group = []
new_group.append(self.group[0])
#贵族
for i in range(1,_noble):
_rand = random.random()
if(0.9>_rand):
new_group.append(self.group[i])
#平民
for i in range(_noble,self.group_size):
_rand = random.random()
if(0.6>_rand):
new_group.append(self.group[i])
self.group = new_group
#繁衍(通过基因转换,构造新的种群)
def Propagate(self):
#繁衍第一步,随机选择父本和母本
_len_group = len(self.group)
_num = self.group_size - _len_group
for _i in range(_num):
#随机选择父本和母本
_father = random.randint(0,_len_group-1)
_mother = random.randint(0,_len_group-1)
_gp = random.randint(0,31)#选择基因交换位置
_ = individual()
_.gene = self.group[_father].gene[0:_gp]+self.group[_mother].gene[_gp:32]
self.group.append(_)
#进行变异
def mutation(self):
#国王不发生变异,其余个体按照变异率进行变异
for _i in range(1,self.group_size):
_rand = random.random()
if(self.mutationprop>_rand):
_gp = random.randint(0,31)#选择基因变异的位置
if(self.group[_i].gene[_gp]==1):
self.group[_i].gene[_gp] = 0
else:
self.group[_i].gene[_gp] = 1
#打印国王信息
def showtheking(self):
print("国王的信息")
print("适应度",self.group[0].fitness)
print("系数W",self.group[0].W[0],self.group[0].W[1],self.group[0].W[2])
print("系数Q",self.group[0].Q[0],self.group[0].Q[1],self.group[0].Q[2])
print("函数的最优解",-np.log(self.group[0].fitness))
def showgroup(self):
for i in range(self.group_size):
print("适应度",self.group[i].fitness)
print("系数W",self.group[i].W[0],self.group[i].W[1],self.group[i].W[2])
print("系数Q",self.group[i].Q[0],self.group[i].Q[1],self.group[i].Q[2])
print("函数的值",-np.log(self.group[i].fitness))
def run(self,_cyclenum):
for _i in range(_cyclenum):
self.choose()
self.Propagate()
self.mutation()
self.showgene()
#self.showtheking()
self.showgroup()
self.showtheking()
#file main.py
from plugin import GA
if __name__ == "__main__":
_ga =GA(4000,3.62,0.2)
_ga.run(400)
使用Python或者OCtave,matlab等编程语言进行开发是十分有必要的,先用便捷的编程语言验证算法的可行性,再用C++/Java去实现算法,这一点对算法工程师来说,尤为重要。读者可以加入QQ群,交流学习Python
916372346。