假设函数,其中。试用遗传算法求解y的最大值,请仿照例4.1(参考课件第三章“遗传算法的流程”)写出关键的求解步骤。
import random
import math
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
'''产生初始种群'''
def initialpopulation(NP,n,x0,x1):
'''NP代表种群规模,n代表目标函数的未知量的个数;
x0代表未知数取值的下限,x1代表未知数取值的上限'''
initial=[]
for i in range(NP):
n_initial=[random.uniform(x0,x1) for j in range(n)]
initial.append(n_initial)
return initial
'''标定适值函数'''
def fitnessfunction(X):
'''X代表存储各个未知量的取值的列表'''
return 1/(math.sqrt(X[0]**2)+math.sqrt(X[1]**2)+math.sqrt(X[2]**2)+math.sqrt(X[3]**2)+1)
'''采用轮盘赌选择算法选择个体'''
def selection(NP,X0):
'''NP代表种群规模,X0代表种群'''
#计算种群中各个个体的适应值
value=[]
for i in range(NP):
value.append(fitnessfunction(X0[i]))
'''计算适应度和累计概率函数'''
#计算选择概率
fsum=0
for i in range(NP):
fsum=fsum+value[i]**2
value_ratio=[]
for i in range(NP):
value_ratio.append((value[i]**2)/fsum)
#计算累加概率
value_ratio_add=[]
for i in range(NP):
if i==0:
value_ratio_add.append(value_ratio[i])
else:
value_ratio_add.append(value_ratio_add[i-1]+value_ratio[i])
#产生[0,1]之间的随机数,进行NP次轮转
random_ratio=[random.uniform(0,1) for i in range(NP)]
#进行轮盘赌选择
choose_index=[] #从0开始计
value_ratio_add0=[0,*value_ratio_add] #在列表value_ratio_add的最前面加上一个0
for i in range(NP):
for j in range(NP):
if random_ratio[i]>=value_ratio_add0[j] and random_ratio[i]<value_ratio_add0[j+1]:
choose_index.append(j)
break
#得到经过轮盘赌选择算法后的种群
population=[X0[i] for i in choose_index]
return population
'''遗传运算——单切点交叉'''
def crossover1(X0,pc,NP,n):
'''X0代表种群,pc代表交叉概率,NP代表种群规模,n代表染色体上的基因数目'''
#对每个染色体生成一个[0,1]之间的随机数
random_crossover=[random.uniform(0,1) for i in range(NP)]
#判断哪些染色体进行交叉运算
crossover_index=[] #种群中进行交叉运算的染色体的索引值
for i in range(NP):
if random_crossover[i]<pc:
crossover_index.append(i)
#判断初步确定的需要交叉的染色体个数,如果为奇数,则最后一个染色体不进行交叉运算
if (len(crossover_index)%2)!=0:
crossover_index.pop()
crossover_index=crossover_index
#进行单切点交叉
if len(crossover_index)!=0:
randint_index=[random.randint(0,n-2) for i in range(int(len(crossover_index)/2))] #选择切点
for i in range(0,len(crossover_index),2):
crossover1=X0[crossover_index[i]]
crossover2=X0[crossover_index[i+1]]
crossoverindex=randint_index[int(i/2)]
#分割
crossover1_0=[crossover1[j] for j in range(crossoverindex+1)]
crossover1_1=[crossover1[j] for j in range(crossoverindex+1,n)]
crossover2_0 = [crossover2[j] for j in range(crossoverindex + 1)]
crossover2_1 = [crossover2[j] for j in range(crossoverindex + 1, n)]
#交换
X0[crossover_index[i]]=[*crossover1_0,*crossover2_1]
X0[crossover_index[i+1]]=[*crossover2_0,*crossover1_1]
#返回进行单切点交叉后的种群
return X0
'''遗传运算——双切点交叉'''
def crossover2(X0,pc,NP,n):
'''X0代表种群,pc代表交叉概率,NP代表种群规模,n代表染色体上的基因数目'''
# 对每个染色体生成一个[0,1]之间的随机数
random_crossover=[random.uniform(0, 1) for i in range(NP)]
# 判断哪些染色体进行交叉运算
crossover_index=[] # 种群中进行交叉运算的染色体的索引值
for i in range(NP):
if random_crossover[i]<pc:
crossover_index.append(i)
# 判断初步确定的需要交叉的染色体个数,如果为奇数,则最后一个染色体不进行交叉运算
if (len(crossover_index)%2)!=0:
crossover_index.pop()
crossover_index=crossover_index
#进行双切点交叉
if len(crossover_index)!=0:
randint_index=[sorted(random.sample([i for i in range(0,n-1)],2)) for i in range(int(len(crossover_index)/2))]
for i in range(0,len(crossover_index),2):
crossover1=X0[crossover_index[i]]
crossover2=X0[crossover_index[i+1]]
crossoverindex=randint_index[int(i/2)]
#分割
crossover1_1=[crossover1[j] for j in range(crossoverindex[0]+1)]
crossover1_2=[crossover1[j] for j in range(crossoverindex[0]+1,crossoverindex[1]+1)]
crossover1_3=[crossover1[j] for j in range(crossoverindex[1]+1,n)]
crossover2_1=[crossover2[j] for j in range(crossoverindex[0]+1)]
crossover2_2=[crossover2[j] for j in range(crossoverindex[0]+1,crossoverindex[1]+1)]
crossover2_3=[crossover2[j] for j in range(crossoverindex[1]+1,n)]
#交换
X0[crossover_index[i]]=[*crossover1_1,*crossover2_2,*crossover1_3]
X0[crossover_index[i+1]]=[*crossover2_1,*crossover1_2,*crossover2_3]
#返回进行双切点交叉后的种群
return X0
'''进行遗传运算——变异'''
def mutation(X0,pm,NP,n,x0,x1):
'''X0代表种群,pm代表交叉概率,NP代表种群规模,n代表染色体上的基因数目
x0代表未知数取值的下限,x1代表未知数取值的上限'''
#生成在[0,1]上的随机数列表
random_gene=[[random.uniform(0,1) for i in range(n)] for j in range(NP)]
#进行变异运算
for i in range(NP):
for j in range(n):
if random_gene[i][j]<pm:
X0[i][j]=random.uniform(x0,x1)
#返回经过变异操作后的种群
return X0
'''计算种群中所有个体的适应值并返回最大值'''
def fitnessmax(X0,NP):
'''X0代表种群,NP代表种群规模'''
#计算种群中各个个体的适应值
value=[]
for i in range(NP):
value.append(fitnessfunction(X0[i]))
value_max=max(value)
#适应值最大所对应的索引值
index_max=value.index(max(value))
#适应值最大所对应的染色体
X0_max=X0[index_max]
return value_max,X0_max
'''计算种群的平均适应值'''
def fitness_avg(X0,NP):
'''X0代表种群,NP代表种群规模'''
#计算种群中各个个体的适应值
value=[]
for i in range(NP):
value.append(fitnessfunction(X0[i]))
#平均适应值
value_avg=sum(value)/NP
return value_avg
'''使用单切点交叉的遗传算法'''
def GA1(NP,NG,n,x0,x1,pc,pm):
'''NP代表种群规模,NG代表最大代数,n代表一个染色体的基因数
x0代表未知数取值的下限,x1代表未知数取值的上限
pc代表交叉概率,pm代表变异概率'''
#遗传算法——单切点交叉
print("----------------------------------------------------------遗传算法(单切点交叉)----------------------------------------------------------")
#产生初始种群
X0=initialpopulation(NP,n,x0,x1)
#存储每一代最大适应值和对应的函数值的列表
fitnessmax_list=[]
X0max_list=[]
#历史最大适应值和对应的函数值
history_max=0
history=[]
history_X0=[]
for i in range(NG):
'''得到种群的最大适应值和对应的染色体'''
value_max,valueX0_max=fitnessmax(X0,NP)
fitnessmax_list.append(value_max)
X0max_list.append(valueX0_max)
if i==0:
history_max=value_max
history.append(history_max)
history_X0.append(valueX0_max)
else:
if value_max>=history_max:
history_max=value_max
history.append(history_max)
history_X0.append(valueX0_max)
else:
history.append(history_max)
history_X0.append(history_X0[i-1])
print("第{}代:{} value_max={}".format(i + 1, history_X0[i], history[i]))
'''选择'''
X1=selection(NP,X0)
'''双切点交叉运算'''
X2=crossover1(X1,pc,NP,4)
'''变异运算'''
X3=mutation(X2,pm,NP,4,-10,10)
X0=X3
print("最优解Best={}".format(history[-1]))
print("---------------------------------------------------------------进程结束---------------------------------------------------------------")
'''绘制随着代数的增加每一代的最大适应值和历史最大适应值的变化'''
ax1=plt.subplot(111)
ax1.plot(range(1,NG+1),fitnessmax_list,c='plum',label="每一代的最大适应值")
ax1.set_ylabel("适应值")
ax1.set_xlabel("代数")
plt.title("遗传算法(单切点交叉)每一代的最大适应值随代数的变化")
ax1.legend()
plt.show()
ax2=plt.subplot(111)
ax2.plot(range(1,NG+1),history,c='orange',label="历史最大适应值")
ax2.set_ylabel("适应值")
ax2.set_xlabel("代数")
plt.title("遗传算法(单切点交叉)的优化过程")
ax2.legend()
plt.show()
return fitnessmax_list[-1],history[-1],X0max_list[-1],history_X0[-1]
'''使用双切点交叉的遗传算法'''
def GA2(NP,NG,n,x0,x1,pc,pm):
'''NP代表种群规模,NG代表最大代数,n代表一个染色体的基因数
x0代表未知数取值的下限,x1代表未知数取值的上限
pc代表交叉概率,pm代表变异概率'''
#遗传算法——单切点交叉
print("----------------------------------------------------------遗传算法(双切点交叉)----------------------------------------------------------")
#产生初始种群
X0=initialpopulation(NP,n,x0,x1)
#存储最大适应值和对应的函数值的列表
fitnessmax_list=[]
X0max_list=[]
#历史最大适应值
history_max=0
history=[]
history_X0=[]
for i in range(NG):
'''得到种群的最大适应值和对应的染色体'''
value_max,valueX0_max=fitnessmax(X0,NP)
fitnessmax_list.append(value_max)
X0max_list.append(valueX0_max)
if i==0:
history_max=value_max
history.append(history_max)
history_X0.append(valueX0_max)
else:
if value_max>=history_max:
history_max=value_max
history.append(history_max)
history_X0.append(valueX0_max)
else:
history.append(history_max)
history_X0.append(history_X0[i-1])
print("第{}代:{} value_max={}".format(i + 1, history_X0[i], history[i]))
'''选择'''
X1=selection(NP,X0)
'''双切点交叉运算'''
X2=crossover2(X1,pc,NP,4)
'''变异运算'''
X3=mutation(X2,pm,NP,4,-10,10)
X0=X3
print("最优解Best={}".format(history[-1]))
print("---------------------------------------------------------------进程结束---------------------------------------------------------------")
'''绘制随着代数的增加最大适应值的变化'''
ax1=plt.subplot(111)
ax1.plot(range(1,NG+1),fitnessmax_list,c='plum',label="每一代的最大适应值")
ax1.set_ylabel("适应值")
ax1.set_xlabel("代数")
plt.title("遗传算法(双切点交叉)每一代的最大适应值随代数的变化")
ax1.legend()
plt.show()
ax2=plt.subplot(111)
ax2.plot(range(1,NG+1),history,c='orange',label="历史最大适应值")
ax2.set_ylabel("适应值")
ax2.set_xlabel("代数")
plt.title("遗传算法(双切点交叉)的优化过程")
ax2.legend()
plt.show()
return fitnessmax_list[-1],history[-1],X0max_list[-1],history_X0[-1]
'''主函数'''
if __name__=="__main__":
'''规定最大代数'''
NG=1000
'''规定种群规模'''
NP=100
'''规定交叉率'''
pc=0.9
'''规定变异率'''
pm=0.1
'''规定一个染色体上的基因数'''
n=4
'''规定未知数的下限'''
x0=-10
'''规定未知数的上限'''
x1=10
'''存储遗传算法中单切点交叉和双切点交叉最后得到的最大适应值及对应的未知数取值'''
fitness_max=[]
fitnessX0_max=[]
'''进行单切点交叉的遗传算法'''
value_max1,historymax1,valueX0_max1,historymaxX0_1=GA1(NP,NG,n,x0,x1,pc,pm)
fitness_max.append(historymax1)
fitnessX0_max.append(historymaxX0_1)
'''进行双切点交叉的遗传运算'''
value_max2,historymax2,valueX0_max2,historymaxX0_2=GA2(NP,NG,n,x0,x1,pc,pm)
fitness_max.append(historymax2)
fitnessX0_max.append(historymaxX0_2)
print("单切点交叉的最优解:{}\t对应的未知数取值:{}\n双切点交叉的最优解:{}\t对应的未知数取值:{}".format(fitness_max[0],fitnessX0_max[0],fitness_max[1],fitnessX0_max[1]))
第一次运行的结果:
第二次运行的结果: