差分进化算法
- 差分进化算法是一种数值优化解法,研究生课程的数值分析方法中有很多类似的思想。
- 差分进化算法最关键的公式就是产生新解的公式,使用三个旧解产生一个新解。公式如下:
X n e w = X 1 + F ∗ ( X 2 − X 3 ) \large X_{new} = X_1 +F *(X_2-X_3) Xnew=X1+F∗(X2−X3)
差分进化算法流程图
自适应的 λ \lambda λ
- λ \lambda λ控制的是变异时加权差的权重;加权差又是什么,在这个算法里面,变异操作实际上就是一种差分操作。
- 公式如下:,用三个不相同的解通过加权差加到另一个解上产生新的解。
- 如上公式中的F就是这个权。自适应的权需要随着迭代进程发生变化,公式如下:
- 这个 G m G_m Gm表示当前迭代次数,G表示最大迭代次数, F 0 F_0 F0表示初始权。
- 可以把 λ \lambda λ画出来看一下,设置G=100,如图所示:
自适应的 λ \lambda λ可视化
- 可以看到随着迭代次数增多, λ \lambda λ逐渐变小;意思就是随着迭代的增加,我们希望变异时,解的波动范围应该变小,从而引导解的收敛。
Python代码
f ( x ) = ∑ i = 1 n x i 2 ( − 20 ⩽ x i ⩽ 20 ) \large f(x)=\sum_{i=1}^{n} x_{i}^{2}\left(-20 \leqslant x_{i} \leqslant 20\right) f(x)=i=1∑nxi2(−20⩽xi⩽20)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from numpy import random
class DE(): # differential evolution-->DE
def __init__(self,NP,D,G,F0,Pc,Xs,Xx,E):
'''
:param NP: 种群数量
:param D: 解维度
:param G: 最大迭代次数
:param F0: 初始变异算子
:param Pc: 交叉概率-->这里交叉的意思,是用一个中间变量存放可能的变异解和不发生变异的解,后面再把这个中间变量还给初始解变量
:param Xs: 解上限
:param Xx: 解下限
:param E: 阈值
'''
self.NP = NP
self.D = D
self.Xs = Xs
self.Xx = Xx
self.E = E
self.Pc = Pc
self.G = G
self.F0 = F0
def func(self,x):
return sum(x**2)
def de(self):
x = random.rand(self.NP,self.D)*(self.Xs-self.Xx) + self.Xx
v = np.zeros((self.NP,self.D))
u = np.zeros((self.NP,self.D))
y = self.func(x.T)
trace = []
trace.append(min(y))
g = 0
deta = 1e-10
while y[0] > self.E:
# for g in range(self.G):
''' 变异操作'''
# 自适应变异算子
lamda = np.exp(1-self.G/(self.G+1-g))
F = self.F0*2**lamda
# 所有的解都要被变异一次
# 确保选择的x1,x2,x3和当前被变异的解xn各不相同
for n in range(self.NP):
x1 = random.randint(0, self.D, 1)
while x1 == n:
x1 = random.randint(0, self.D, 1)
x2 = random.randint(0, self.D, 1)
while x2 == n or x2 == x1:
x2 = random.randint(0, self.D, 1)
x3 = random.randint(0, self.D, 1)
while x3 == n or x3 == x1 or x3 ==x2:
x3 = random.randint(0, self.D, 1)
# v接受变异的解空间
v[n] = x[x1] + F*(x[x2] - x[x3])
# 交叉操作
'''扩展解空间:实际上应该是上一步作为扩展,因为交叉概率有可能低;'''
r = random.randint(0,self.D,1) # 生成[0,self.D)的随机整数,1:一个
for d in range(self.D):
p = random.rand()
if p < self.Pc or d == r:
u[:,d] = v[:,d] # 满足交叉条件,u接收d维度上v的所有解
else:
u[:,d] = x[:,d] # 否则接收d维度上x的所有解
# 边界条件处理
k = (u<self.Xx).sum() + (u>self.Xs).sum()
while k > 0:
if (u<self.Xx).sum() > 0:
u[u<self.Xx] = random.rand()*(self.Xs - self.Xx) + self.Xx
elif (u>self.Xs).sum() > 0:
u[u > self.Xs] = random.rand() * (self.Xs - self.Xx) + self.Xx
k = (u < self.Xx).sum() + (u > self.Xs).sum()
# 选择操作
yu = self.func(u.T)
index1 = np.where(yu<y)
x[index1] = u[index1]
y = self.func(x.T)
trace.append(min(y))
# if min(y) < self.E:
# break
g = g + 1
yk = np.sort(y)
index2 = np.argsort(y)
xk = x[index2]
bx = xk[0]
by = yk[0]
return trace,bx,by
def drawer(self):
y, bx,by = self.de()
plt.rc('legend', fontsize=16)
matplotlib.rcParams['font.family'] = 'Kaiti'
fig = plt.figure(figsize=(10,5.5),dpi=100)
plt.plot(y, 'b:d', markerfacecolor='red',markersize=3,linewidth=1.5, label='差分进化算法仿真实例') # 1.线型颜色、线型风格、标记风格;2.线宽 3.标记颜色填充
plt.xlabel('迭代次数', fontproperties='Kaiti', fontsize=14) # 坐标轴标签设置
plt.ylabel('适应度函数值', fontproperties='Kaiti', fontsize=14)
plt.legend() # 添加图例
# 图题
plt.title(r'差分进化算法求解$Min:f(x)=\sum_{i=1}^{n} x_{i}^{2}\left(-20 \leqslant x_{i} \leqslant 20\right)$',
fontproperties='Kaiti', fontsize=14)
plt.annotate('(最小值为:%.4f)'%by,xy=(len(y),by),xytext=(len(y)-40,70),fontproperties='Kaiti',fontsize=14,arrowprops=dict(facecolor='red',shrink=1.5,width=1.5,headwidth=5))
plt.grid(True) # 网格
plt.show()
da = DE(50,10,2000,0.4,0.1,20,-20,1e-6)
y,bx,by = da.de()
da.drawer()
print(by)
实验结果
- 相较于遗传算法,差分进化过程就比较陡峭,不平滑。