已知函数y=f(x1,x2)=1/(x1^2 + x2^2+1),其中-5<=x1,x2<=5,用遗传算法求解y的最大值。
代码
import random
import numpy as np
import copy
max_value = 5 # 区间最大值
min = -5 # 区间最小值
len = max_value - min # 区间长度
chro = 6 # 染色体条数
G = 500 # 最大遗传代数
Pc = 0.8 # 交叉概率
Pm = 0.1 # 变异概率
# 求编码长度
def len_code(l):
i = 0
while True:
if 2**(i-1) < l*10**4 < 2**i-1:
# 由于需要表示x1和x2,因此返回长度应该是所求长度的两倍
return 2*i
i += 1
# 解码
def decode(x , len_area , len_code , min):
left = x[:len_code] # 将左半部分取出来作为x1
# 由于得到的left是列表,为了进行后续的进制转转,需要将其先转换为字符串
x1_str = ''.join(left)
x1_dec=int(x1_str, 2) # 将二进制转转为十进制
right = x[len_code:] # 将右半部分取出来作为x1
# 由于得到的right是列表,为了进行后续的进制转转,需要将其先转换为字符串
x2_str = ''.join(right)
x2_dec = int(x2_str , 2) # 将二进制转转为十进制
x1 = min + x1_dec*len_area/(2**len_code-1)
x2 = min + x2_dec*len_area/(2**len_code-1)
return x1 , x2
# 计算适应度函数值
def f_value(population , L):
# value由于存放每一组染色体的适应度函数值
value = []
# 遍历初始种群,计算每一个个体的适应度函数值
for item in population:
new_item = []
for e in item:
# 为了后续计算的方便,将每一个个体的0,1转换为字符形式
new_e=str(e)
new_item.append(new_e)
# 计算x1,x2的值
x1, x2 = decode(new_item, len, int(L / 2), min)
# 计算个体适应度函数值,并将其追加到value列表中
fit = round(1/(x1**2 + x2**2 + 1) , 4)
value.append(fit)
return value
# 计算被选择的概率和累积概率
def prob(v):
prob_slect = [] # 初始化被选择概率
prob_accum = [0]*chro # 初始化累积概率
total = sum(v) # 求当前种群适应度的和
for i in range(chro):
# 被选择概率为个体的适应度值比上种群适应度和
prob_slect.append(round(v[i] / total , 4))
# 累积概率为当前个体之前的适应度值之和
prob_accum[i] = round(sum(prob_slect) , 4)
return prob_accum
# 轮盘赌选择
def roulette(former , probility):
selection = [0]*chro
for i in range(chro):
random_num = round(random.random() , 4)
for j in range(chro):
if random_num < probility[0]:
selection[i] = 0
elif probility[j] < random_num < probility[j+1]:
selection[i] = j+1
# print(selection)
select = []
for e in selection:
select.append(former[e])
return select
# 单点交叉
def cross(chromosome , L):
# print('1:',chromosome)
# 定义新的列表用于存放交叉后的染色体
chromosome_copy = copy.deepcopy(chromosome)
new_chromosome = chromosome_copy.copy()
i = 0
while i < chro:
# 产生chro/2个0到1之间的随机小数作为作为是否交叉的依据,并保留小数点后四位
random_num = (round(random.random() , 4))
# 产生L个随机整数作为作为交叉位置
random_location = random.randint(0,L)
# print('num:',random_num)
# print('loc:',random_location)
# 当随机数小于交叉概率时,进行交叉
if random_num < Pc:
# 交叉操作
new_chromosome[i][random_location:] = chromosome_copy[i+1][random_location:]
# 将经过交叉操作的染色体放入新染色体列表中
new_chromosome[i+1][random_location:] = chromosome_copy[i][random_location:]
i += 2
return new_chromosome
# 单点变异
def variation(chromosome , L):
# 产生一个chro*L大小的0到1之间的随机小数矩阵
random_var = np.random.random((chro , L))
# print(random_var)
for i in range(chro):
for j in range(L):
# 当随机数小于变异概率时,进行变异
if random_var[i][j] < Pm:
# print(i,j)
# 由于变异操作就是0,1的互换,因此可把当前数减一,再取绝对值来表示此操作
chromosome[i][j] = abs(chromosome[i][j] - 1)
return chromosome
# 主函数
def main():
L = len_code(len) # 编码长度
# 随机初始化种群
initial = np.random.randint(0, 2, (chro, L))
# print(initial)
i = 0
while i < G:
# print(i)
# 计算种群适应度函数值
if i == 0:
value = f_value(initial.copy() , L)
else:
value = f_value(var_gene.copy() , L)
# print(value)
# 计算种群累积概率
accumulate = prob(value)
# print(accumulate)
# 进行轮盘赌选择
if i == 0:
sel_gene = roulette(initial.copy() , accumulate)
else:
sel_gene = roulette(var_gene.copy() , accumulate)
# 单点交叉
cross_gene = cross(sel_gene.copy() , L)
# 单点变异
var_gene = variation(cross_gene.copy() , L)
var_value = f_value(var_gene.copy() , L)
if max(var_value) < max(value):
var_gene = sel_gene
i += 1
final_value = f_value(var_gene.copy() , L)
print("用遗传算法求得该函数的最大值为:" , max(final_value))
if __name__ == '__main__':
main()
运行结果
图片:
最近比较忙,之后有时间会详细介绍遗传算法及该代码,代码全为自己编写,注释详细,个人认为理解起来容易,望大家支持,有不懂或觉得代码有问题的地方可在评论区指出~