一、实验目的
(1)熟悉遗传算法的基本进化思想和基本流程;
(2)理解遗传算法中遗传算子(选择、交叉、变异)的设计思想;
(3)重点编程实现利用基本遗传算法求解连续优化问题——二元函数极值或最值问题。
二、编程环境
Python语言、Matlab语言、C语言等。
三、问题描述与算法设计
(1)问题1:求二元函数的最大值。
![]()
图像如下图所示,显然函数存在多个极值。

问题2:求二元函数的最大值。

图像如下图所示,显然函数存在多个极值。

(2)参数值:
初始化种群数目:NP=自定
染色体二进制编码长度:L=自定
最大进化代数:G=自定
交叉概率:Pc =0.8
变异概率:Pm =0.1
自变量x的定义域上限:Xs=7
自变量x的定义域下限:Xx=0
(3)编程中的关键问题:
(a) 编码。每个染色体编码成长度为6的二进制串,比如101011。(这里地编码,大家可以重新设计,自由发挥。)
(b) 初始种群。初始种群随机产生,种群规模为40个。
(c) 解码。将二进制数串解码为十进制数
(d) 适应度值。因为求解的是最大值,所以适应度值就是将自变量代入函数后的函数值。
(e) 交叉。交叉采用两点交叉。
(f) 变异。变异采用单点、取反变异
(g) 选择。取上一代种群和交叉变异后的种群的最好的一半。
四、基本遗传算法的一般步骤
第一步:使用随机方法产生一个有NP个染色体的初始种群;
第二步:计算种群中每一个染色体的适应度值,即函数值;
第三步:若达到最大迭代次数G,则算法终止;否则,继续迭代;
第四步:按照概率执行两点交叉操作。将种群分为奇偶两个子种群,即种群中的第1、3、…等归为奇子群,其余为偶子群;然后将两个子种群中的对应个体按照概率Pc执行两点交叉。
第五步:按照概率执行单点变异操作。即在一个染色体中随机选择一个基因位置,若为0则变为1,若为1则变为0;
第六步:将交叉变异前与后的种群,混合在一起,选择适应度值最大的一半,作为下一代种群。
第七步:返回第三步。
五、源代码
# 种群数
population_size=40
generations=200
chorm_length=6
# 交配概率
pc=0.8
# 变异概率
pm=0.1
# 基因编码
genetic_population=[]
# 种群对应的【0,10】
population=[]
fitness=[]
fitness_mean=[]
# 每次迭代所获得的最优解
optimum_solution=[]
bestx_list=[]
besty_list=[]
# 对染色体进行0,1编码,生成初始种群
def chrom_encoding():
for i in range(population_size):
population_i=[]
for j in range(2*chorm_length):
population_i.append(random.randint(0,1))
# print(population_i)
genetic_population.append(population_i)
# 解码
def chorm_decoding():
population.clear()
for i in range(population_size):
s=[]
valuex=0
valuey=0
for j in range(chorm_length):
valuex+=genetic_population[i][j]*(2**(chorm_length-1-j))
for j in range(chorm_length,chorm_length*2):
valuey+=genetic_population[i][j]*(2**(chorm_length*2-1-j))
s.append(valuex*10/(2**(chorm_length)-1))
s.append(valuey*10/(2**(chorm_length)-1))
population.append(s)
# print(population)
def problem_function(x, y):
sumx = 0
sumy = 0
for i in range(1,6):
sumx = sumx + (i*math.cos((i+1)*x+i))
sumy = sumy + (i*math.cos((i+1)*y+i))
return sumx*sumy
def calculate_fitness():
sum=0.0
fitness.clear()
for i in range(population_size):
function_value=problem_function(population[i][0],population[i][1])
if function_value>0.0:
sum+=function_value
fitness.append(function_value)
else:
fitness.append(0.0)
return sum/population_size,fitness
def best_value():
max_fitness=fitness[0]
max_chorm=0
for i in range(population_size):
if fitness[i]>max_fitness:
max_fitness=fitness[i]
max_chorm=i
return max_chorm,max_fitness,population[max_chorm][0],population[max_chorm][1]
# 轮盘赌
def selection():
fitness_array = np.array(fitness)
new_population_id = np.random.choice(np.arange(population_size), (population_size,),
replace=True, p=fitness_array/fitness_array.sum())
new_genetic_population = []
global genetic_population
for i in range(population_size):
new_genetic_population.append(genetic_population[new_population_id[i]])
genetic_population = new_genetic_population
# 交叉采用两点交叉
def crossover():
for i in range(0,population_size-1,2):
if random.random()<pc:
change_pointa=random.randint(0,2*chorm_length-1)
change_pointb=random.randint(change_pointa,2*chorm_length-1)
temp1=[]
temp2=[]
temp1.extend(genetic_population[i][0:change_pointa])
temp1.extend(genetic_population[i+1][change_pointa:change_pointb])
temp1.extend(genetic_population[i][change_pointb:])
temp2.extend(genetic_population[i+1][0:change_pointa])
temp2.extend(genetic_population[i][change_pointa:change_pointb])
temp2.extend(genetic_population[i+1][change_pointb:])
genetic_population[i] = temp1
genetic_population[i+1] = temp2
# 变异
def mutation():
for i in range(population_size):
if random.random()<pm:
mutation_point=random.randint(0,2*chorm_length-1)
if genetic_population[i][mutation_point]==0:
genetic_population[i][mutation_point]=1
else:
genetic_population[i][mutation_point]=0
# 开始迭代
xy=[]
z=[]
chrom_encoding()
for step in range(generations):
chorm_decoding()
fit_mean,fitness=calculate_fitness()
fit_mean,fitness=calculate_fitness()
best_id,best_fitness,bestx,besty=best_value()
optimum_solution.append(best_fitness)
bestx_list.append(bestx)
besty_list.append(besty)
fitness_mean.append(fit_mean)
if step==1:
xy=population
z=fitness
selection()
crossover()
mutation()
# 最优解随迭代次数的变化
fig1 = plt.figure(1)
plt.plot(range(1, generations + 1), optimum_solution)
plt.xlabel('迭代次数', fontproperties='SimHei')
plt.ylabel('最优解', fontproperties='SimHei')
# 平均适应度随迭代次数的变化
fig2 = plt.figure(2)
plt.plot(range(1, generations + 1), fitness_mean)
plt.xlabel('迭代次数', fontproperties='SimHei')
plt.ylabel('平均适应度', fontproperties='SimHei')
plt.show()
class Ga:
def __init__(self,NP=100,L=20,G=10,Pc=0.8,Pm=0.1,Xs=10,Xx=0,Ys=10,Yx=0,is_max=True) -> None:
self.NP = NP # 种群数目
self.L = L # 染色体编码长度
self.G = G # 最大进化代数
self.Pc= Pc # 交叉概率
self.Pm = Pm # 变异概率
self.Xs = Xs # x边界
self.Xx = Xx
self.Ys = Ys # y边界
self.Yx = Yx
self.choose = []
self.is_max = is_max # 是否求最大值
# 编码
def generate_population(self):
l = 2
'''产生种群 已经编码好 0 1编码长度 L'''
x = np.random.randint(2, size=(self.NP, self.L))
y = np.random.randint(2, size=(self.NP, self.L))
# return np.array([np.random.randint(2, size=(NP, L)) for i in range(l)])
return x,y
# 解码函数
def decode(self,x,y):
# 进行解码
X = x.dot(2**np.arange(self.L)[::-1])/(2**self.L-1)*(self.Xs-self.Xx)+self.Xx
Y = y.dot(2**np.arange(self.L)[::-1])/(2**self.L-1)*(self.Ys-self.Yx)+self.Yx
return X,Y
# 自定义函数
def f(self,x,y):
return x**2+y**2
# 自定义适应度,求最大值和最小值
def fitness(self,x,y):
re = self.f(x,y)
# 由于结果可能为负值 但是再下面的选择阶段不允许出现负值,需要进行处理
# 0值相当于概率0,所以需要加个非常小的正数
if self.is_max: # 选最大值
re = re - np.min(re) + 1e-5
else:
re = np.max(re) - re + 1e-5
return re
def select_population(self,pre_x,pre_y,x,y):
x_ ,y_ =self.decode(x,y)
result = self.fitness(x_,y_)
# 挑选适应度高的个体 规模为原始的一半////轮盘赌
# 抽取序号
index = np.random.choice(np.arange(self.NP),replace=True,size=self.NP,p=result/result.sum())
# pre_x_ ,pre_y_ =self.decode(x,y)
# result = self.fitness(pre_x_ ,pre_y_,True)
# index_pre = np.random.choice(np.arange(self.NP),replace=True,size=self.NP//2,p=result/result.sum())
# # 取上一代种群和交叉变异后的种群的最好的一半
# selected_x =np.concatenate([x[index], pre_x[index_pre]], axis=0)
# selected_y =np.concatenate([y[index], pre_y[index_pre]], axis=0)
selected_x = x[index]
selected_y = y[index]
self.choose.append(self.decode(selected_x,selected_y))
return selected_x,selected_y
def cross_mutation(self,x,y):
father = []
father.extend(x)
father.extend(y)
children = []
for i in father:
child = i
# 交叉操作
if np.random.rand() < self.Pc:
# 产生随机交叉点
point = np.random.randint(self.L)
# 选取母节点
# print(point)
child[point:] = i[point:]
# 变异操作
if np.random.rand() < self.Pm:
point = np.random.randint(self.L)
child[point]^=1 # 取反
children.append(child)
return np.array(children[:len(children)//2]),np.array(children[len(children)//2:])
def population_iteration(self):
self.process = []
x,y = self.generate_population()
# x , y= decode(x,y)
for i in range(self.G):
pre_x,pre_y = x , y
x,y = self.select_population(pre_x,pre_y,x,y)
x,y = self.cross_mutation(x,y)
a,b =self.decode(x,y)
self.process.append(self.f(a,b).sum())
self.x ,self.y= self.decode(x,y)
self.plot_3d()
self.plot_coss()
def plot_3d(self):
fig = plt.figure(figsize=(10,7))
ax = Axes3D(fig)
X = np.linspace(self.Xs,self.Xx,100)
Y = np.linspace(self.Ys,self.Yx,100)
X,Y = np.meshgrid(X, Y)
Z = self.f(X, Y)
ax.plot_surface(X,Y,Z,rstride=1, cstride=1, cmap='rainbow')
# ax.set_zlim(-10,10)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.scatter(self.x,self.y,self.f(self.x,self.y),c='black')
plt.title("result")
plt.show()
def plot_coss(self):
plt.plot(range(len(self.process)),self.process)
plt.title("Total Population Values")
plt.show()
六、实验结果
第一个函数



第二个函数


求解函数极值问题&spm=1001.2101.3001.5002&articleId=162258546&d=1&t=3&u=c3ce0d6b062245e1a250eba57a9da032)
1万+

被折叠的 条评论
为什么被折叠?



