遗传算法
下面是修改封装过后的正确代码
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import random as rd
import time
plt.rcParams['font.serif'] = 'Times New Roman'
plt.rcParams['font.size'] = 10.0
plt.rcParams['xaxis.labellocation'] = 'right'
plt.rcParams['yaxis.labellocation'] = 'top'
# print(plt.rcParams.keys())
def select(inti_pop,popsize,GENE_LEN,size,lb,ub,F): # 选择
fitness,X= Decode_fitness(inti_pop,popsize,GENE_LEN,size,lb,ub,F)
ind = np.random.choice(a=np.arange(popsize), size=popsize, replace=True, p=fitness)
return inti_pop[ind],X,fitness.max()
def Decode_fitness(inti_pop,popsize,GENE_LEN,size,lb,ub,F): # 基因解码并计算适应度的值,返回适应度概率
x = np.zeros((popsize, size)) # 记录每个基因产生的X
for i in range(popsize): # self.inti_pop【i】中的每一个种子基因,# 遍历每一个基因,然后计算基因对应的X值
single = inti_pop[i].reshape(size, GENE_LEN) # 将每一个基因拆分成指定的个数
for j in range(size): #
bin_x = ''.join(single[j]) # 转换成二进制解码所需要的形式:01010100101的字符串
x[i][j] = lb[j] + int(bin_x, 2) / (2 ** GENE_LEN - 1) * (ub[j] - lb[j]) # 解码为十进制
values = F(x) # 计算函数值,以便计算适应度概率值
values[values < 0] = 1e-2
fitness = values # -values.min()+1e-1#防止适应度出现负值,导致无法计算适应度
return fitness / fitness.sum(),x
def cross(inti_pop,popsize,GENE_LEN,size,cross_P): # 交叉
for _ in range(int(popsize)): # 循环若干次
ind = np.random.choice(range(popsize), 2) # 随机选取两个父母的编号
ind_fa, ind_mo = ind[0], ind[1] # 挑选出父母的编号
father = inti_pop[ind_fa] # 父亲
# mather = inti_pop[ind_mo] # 母亲
if rd.random() < cross_P: # 按照概率执行交叉操作
cross_point = rd.randint(0, GENE_LEN * size - 1) # 随机选取交叉点
inti_pop[ind_mo][:cross_point] = father[:cross_point] # 一 fa:BA , mo:AB--->>BB
# inti_pop[ind_fa][:cross_point] = father[:cross_point] # fa:ba ,mo:ab -->>aa
return inti_pop
def mutation(inti_pop,size,GENE_LEN,mutation_P): # 对每一个种子按照概率,执行变异操作
NEW_INTI_POP = []
for child in inti_pop:
if rd.random() < mutation_P: # 按概率执行变异操作
ind = rd.randint(0, GENE_LEN * size - 1) # 随机选取变异点 randint包含末位树 是个坑
a = child[ind] # 变异点原本数值
child[ind] = str(int(a) ^ 1) # 重新赋值 与或非运算
NEW_INTI_POP.append(child)
return np.array(NEW_INTI_POP)
def select_cross_mutation(inti_pop,popsize,GENE_LEN,size,lb,ub,cross_P,mutation_P):
# 三个主要的函数先选择,再交叉,再变异!
inti_pop, X,FITNESS_MAX = select(inti_pop,popsize,GENE_LEN,size,lb,ub,F) # 选择
inti_pop = cross(inti_pop,popsize,GENE_LEN,size,cross_P=cross_P) # 交叉
inti_pop = mutation(inti_pop,size,GENE_LEN,mutation_P=mutation_P) # 变异
return X,inti_pop,FITNESS_MAX #x,y主要用于画图,所以每循环一次就要return
def GETX(X,GENE_LEN,NV,lb,ub):#NV:Number of variables
lb = np.array(lb);ub = np.array(ub)#convert to array
geneX = X.reshape(NV,GENE_LEN)
G_number = np.array(list(map(lambda x:int(''.join(x),2),geneX)))#Decoding the Numbers
real_X = lb + G_number/np.power(2,GENE_LEN)*(ub-lb)
return real_X
def windows(lb,ub):
sns.set_style('darkgrid')
plt.xlim(lb[0]-1,ub[0]+1)
plt.ylim(lb[1]-1,ub[1]+1)
plt.xlabel('First Dimension')
plt.ylabel('Second Dimension')
plt.pause(2)
plt.show()
class GA():
def __init__(self,OF,popsize,gene_length,Iteration,Length_of_X,lb,ub,timeout=10,cross_P=0.6,mutation_P=0.01,PF=0,):
self.NAME = 'GA'
self.PF = PF#Penalty function
self.Func = OF #Object Function
self.Iteration = Iteration #Iteration
self.bestY = []#Record best valueY
self.popsize = popsize#the size of population
self.GENE_LEN = gene_length#length of gene
self.Length_of_X = Length_of_X#amount of variences
self.lb =lb ; self.ub=ub#constraints
self.cross_P = cross_P;self.mutation_P = mutation_P
self.timeout = timeout
def run(self):#主程序
Process_P = []#record the best value of every Iteration
fig = plt.figure()
plt.ion() # 将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
windows(self.lb,self.ub)
inti_pop = np.random.randint(0, 2, size=(self.popsize, self.GENE_LEN * self.Length_of_X)).astype('str') # Initialize
best_y = -np.inf
t1 = time.perf_counter()
Process = 0
# for Process in range(self.Iteration):
while True:
Process+=1
X, inti_pop, FITNESS_MAX = \
select_cross_mutation(
inti_pop,#初始基因群
self.popsize,
self.GENE_LEN,#基因长度
self.Length_of_X,#变量个数
self.lb, self.ub,
cross_P = self.cross_P,mutation_P = self.mutation_P
)#return X Population and the MAX fitness X是解码后的数据
Z = self.Func(X)#Object value
# Process_P.append(Z.max())
Process_P.append(FITNESS_MAX.max())
#dynamic widows to observe Function convergence
x,y = X[:,0],X[:,1]
if 'sca' in locals():
sca.remove()
sca = plt.scatter(x, y, marker='o',edgecolor='black',color='blue',alpha=0.3)
plt.title(f'Cycle:{Process+1}/{self.Iteration}')
plt.show()
plt.pause(0.1)
####################################
if Z.max() > best_y:
best_y = Z.max() # use for compare with Z.max
self.bestY.append(best_y)#Record the optimal solution
ind_best = Z.argmax() # return index of best value
GENE_BEST = inti_pop[ind_best]#Record best x
bestX = GETX(GENE_BEST,self.GENE_LEN,self.Length_of_X,self.lb,self.ub)
if np.all(FITNESS_MAX<1/self.popsize+1e-5):break#达到精度退出程序
if time.perf_counter() - t1 > self.timeout:break#超时退出程序
return bestX, self.bestY,Process_P
if __name__=="__main__":
def F(X): # 目标函数
x = X[:,0]
y = X[:,1]
res = np.sin(x*y)*np.cos(x)*np.cos(y)
return res.ravel()
lb = [0,0] # 约束下线
ub = [10,10] # 约束上限
bestX,bestY,Process_P = GA(OF=F,popsize=500,gene_length=24,
Iteration=100,Length_of_X=2,lb=lb,ub=ub,
cross_P=0.6,mutation_P=.01).run()
print(f'bestX:{bestX}\nbestY:{bestY[-1]}')
plt.ioff()
fig,ax = plt.subplots(1,2,)
ax[1].plot(bestY,linestyle='-.')
ax[0].plot(np.array(Process_P),linestyle='-.')
plt.show()
正确代码
import numpy as np
import random as rd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
def F(x, y): # 目标函数
return 3 * (1 - x) ** 2 * np.exp(-(x ** 2) - (y + 1) ** 2) - 10 * (x / 5 - x ** 3 - y ** 5) * np.exp(
-x ** 2 - y ** 2) - 1 / 3 ** np.exp(-(x + 1) ** 2 - y ** 2)
fitF = F # 目标函数
lb = [-3, -3] # 约束下线
ub = [3, 3] # 约束上限
# #算法的基本参数
size = 2 # 变量个数
GENE_LEN = 24 # 基因长度
popsize = 220 # 种群大小
mutation_P = 0.01 # 变异概率
cross_P = 0.6 # 交叉的概率
def select_cross_mutation(inti_pop):
# 三个主要的函数先选择,再交叉,再变异!
def select(inti_pop):#选择
fitness,x1,x2 = Decode_fitness(inti_pop)
ind = np.random.choice(a=np.arange(popsize), size=popsize, replace=True, p=fitness)
return inti_pop[ind],x1,x2,fitness.max()
def Decode_fitness(inti_pop):# 基因解码并计算适应度的值,返回适应度概率
x = np.zeros((popsize, size)) # 记录每个基因产生的X
# 遍历每一个基因,然后计算基因对应的X值
for i in range(popsize): # self.inti_pop【i】中的每一个种子基因
single = inti_pop[i].reshape(size, GENE_LEN) # 将每一个基因拆分成指定的个数
for j in range(size): #
bin_x = ''.join(single[j]) # 转换成二进制解码所需要的形式:01010100101的字符串
x[i][j] = lb[j] + int(bin_x, 2) / (2 ** GENE_LEN - 1) * (ub[j] - lb[j]) # 解码为十进制
# 下面这两部可以重新定义self.fitF函数,进而修改目标函数和简化代码
# -------------------------------------------------------#
x1 = x[:, 0]
y1 = x[:, 1] # 因为有两个参数:x1,x2
values = fitF(x1, y1) # 计算函数值,以便计算适应度概率值
# -------------------------------------------------------#
values[values < 0] = 1e-2
fitness = values#-values.min()+1e-1#防止适应度出现负值,导致无法计算适应度
return fitness / fitness.sum(),x1,y1
def cross(inti_pop): # 交叉
for _ in range(int(popsize)): # 循环若干次
ind = np.random.choice(range(popsize), 2) # 随机选取两个父母的编号
ind_fa, ind_mo = ind[0], ind[1] # 挑选出父母的编号
father = inti_pop[ind_fa] # 父亲
# mather = inti_pop[ind_mo] # 母亲
if rd.random() < cross_P: # 按照概率执行交叉操作
cross_point = rd.randint(0, GENE_LEN * size - 1) # 随机选取交叉点
inti_pop[ind_mo][:cross_point] = father[:cross_point] # 一 fa:BA , mo:AB--->>BB
# inti_pop[ind_fa][:cross_point] = father[:cross_point] # fa:ba ,mo:ab -->>aa
return inti_pop
def mutation(inti_pop): # 对每一个种子按照概率,执行变异操作
NEW_INTI_POP = []
for child in inti_pop:
if rd.random() < mutation_P: # 按概率执行变异操作
ind = rd.randint(0, GENE_LEN * size - 1) # 随机选取变异点 randint包含末位树 是个坑
a = child[ind] # 变异点原本数值
child[ind] = str(int(a) ^ 1) # 重新赋值 与或非运算
NEW_INTI_POP.append(child)
return np.array(NEW_INTI_POP)
#主程序
inti_pop, x, y,FITNESS_MAX = select(inti_pop) # 选择
inti_pop = cross(inti_pop) # 交叉
inti_pop = mutation(inti_pop) # 变异
return x,y,inti_pop,FITNESS_MAX #x,y主要用于画图,所以每循环一次就要return
def plot_3d(ax):
X = np.linspace(-3, 3)
Y = np.linspace(-3, 3)
X, Y = np.meshgrid(X, Y)
Z = fitF(X, Y)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.pause(2)
plt.show()
def run(iteration): # 循环迭代
# fig = plt.figure()
# ax = Axes3D(fig)
# plt.ion() # 将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
# plot_3d(ax)
inti_pop = np.random.randint(0, 2, size=(popsize, GENE_LEN * size)).astype('str') # 初始化
for _ in range(iteration):
x,y,inti_pop,FITNESS_MAX = select_cross_mutation(inti_pop)
# if 'sca' in locals():
# sca.remove()
Z = F(x,y)
# sca = ax.scatter(x, y, Z, c='black', marker='o')
# plt.show()
plt.pause(0.1)
FIT_Y.append(Z.ravel().max())
# FIT_Y.append(np.array(FITNESS_MAX))
return FIT_Y
if __name__ == "__main__":
fit = run(500)
sns.lineplot(data=np.array(fit))
plt.show()
- [2 ] 第二个代码
import numpy as np
import random as rd
import matplotlib.pyplot as plt
from matplotlib import cm
def F(x, y): # 目标函数
return 3 * (1 - x) ** 2 * np.exp(-(x ** 2) - (y + 1) ** 2) - 10 * (x / 5 - x ** 3 - y ** 5) * np.exp(
-x ** 2 - y ** 2) - 1 / 3 ** np.exp(-(x + 1) ** 2 - y ** 2)
fitF = F # 目标函数
lb = [-3,-3] # 约束下线
ub = [ 3, 3] # 约束上限
# #算法的基本参数
size = 2 # 变量个数
GENE_LEN = 25 # 基因长度
popsize = 220 # 种群大小
mutation_P = 0.01 # 变异概率
cross_P = 0.6 # 交叉的概率
def select(inti_pop): # 选择
fitness, x1, x2 = Decode_fitness(inti_pop)
ind = np.random.choice(a=np.arange(popsize), size=popsize, replace=True, p=fitness)
return inti_pop[ind], x1, x2, fitness.max()
def Decode_fitness(inti_pop): # 基因解码并计算适应度的值,返回适应度概率
x = np.zeros((popsize, size)) # 记录每个基因产生的X
# 遍历每一个基因,然后计算基因对应的X值
for i in range(popsize): # self.inti_pop【i】中的每一个种子基因
single = inti_pop[i].reshape(size, GENE_LEN) # 将每一个基因拆分成指定的个数
for j in range(size): #
bin_x = ''.join(single[j]) # 转换成二进制解码所需要的形式:01010100101的字符串
x[i][j] = lb[j] + int(bin_x, 2) / (2 ** GENE_LEN - 1) * (ub[j] - lb[j]) # 解码为十进制
# 下面这两部可以重新定义self.fitF函数,进而修改目标函数和简化代码
# -------------------------------------------------------#
x1 = x[:, 0]
y1 = x[:, 1] # 因为有两个参数:x1,x2
values = fitF(x1, y1) # 计算函数值,以便计算适应度概率值
# -------------------------------------------------------#
values[values < 0] = 1e-2
fitness = values # -values.min()+1e-1#防止适应度出现负值,导致无法计算适应度
return fitness / fitness.sum(), x1, y1
def cross(inti_pop): # 交叉
for _ in range(int(popsize)): # 循环若干次
ind = np.random.choice(range(popsize), 2) # 随机选取两个父母的编号
ind_fa, ind_mo = ind[0], ind[1] # 挑选出父母的编号
father = inti_pop[ind_fa] # 父亲
# mather = inti_pop[ind_mo] # 母亲
if rd.random() < cross_P: # 按照概率执行交叉操作
cross_point = rd.randint(0, GENE_LEN * size - 1) # 随机选取交叉点
inti_pop[ind_mo][:cross_point] = father[:cross_point] # 一 fa:BA , mo:AB--->>BB
# inti_pop[ind_fa][:cross_point] = father[:cross_point] # fa:ba ,mo:ab -->>aa
return inti_pop
def mutation(inti_pop): # 对每一个种子按照概率,执行变异操作
NEW_INTI_POP = []
for child in inti_pop:
if rd.random() < mutation_P: # 按概率执行变异操作
ind = rd.randint(0, GENE_LEN * size - 1) # 随机选取变异点 randint包含末位树 是个坑
a = child[ind] # 变异点原本数值
child[ind] = str(int(a) ^ 1) # 重新赋值 与或非运算
NEW_INTI_POP.append(child)
return np.array(NEW_INTI_POP)
def select_cross_mutation(inti_pop):
# 三个主要的函数先选择,再交叉,再变异!
#主程序
inti_pop, x, y,FITNESS_MAX = select(inti_pop) # 选择
inti_pop = cross(inti_pop) # 交叉
inti_pop = mutation(inti_pop) # 变异
return x,y,inti_pop,FITNESS_MAX #x,y主要用于画图,所以每循环一次就要return
def plot_3d(ax):
X = np.linspace(-3, 3)
Y = np.linspace(-3, 3)
X, Y = np.meshgrid(X, Y)
Z = fitF(X, Y)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.pause(2)
plt.show()
def run(iteration): # 循环迭代
inti_pop = np.random.randint(0, 2, size=(popsize, GENE_LEN * size)).astype('str') # 初始化
best_y=-np.inf
for _ in range(iteration):
x,y,inti_pop,FITNESS_MAX = select_cross_mutation(inti_pop)
Z = F(x,y)
#保存最优值和最优解
if Z.max()>best_y:
ind_best = Z.argmax()
best_y = Z[ind_best] #
GENE_BEST = inti_pop[ind_best]
return best_y,GENE_BEST
def answer(best_y,GENE_BEST):
def GENE_DECODE(GENE_BEST):
values = []
genes = GENE_BEST.reshape(size, GENE_LEN)
erjinzhishu = np.array(list(map(lambda gene_ :int(''.join(gene_),2),genes)))
for j in range(size):
values.append(lb[j] + erjinzhishu[j]/ (2 ** GENE_LEN - 1) * (ub[j] - lb[j]) ) # 解码为十进制
return values
print(f'BEST_Y:{best_y}')
print(f'BEST_X:{GENE_DECODE(GENE_BEST)}')
if __name__ == "__main__":
best_y,best_x = run(500)
answer(best_y, best_x)