一、初始化
? ? ? ? 不同于NSGA-II,MOEA/D在進行迭代之前需要先進行初始化,初始化的主要內容是計算個體向量權重之間的歐氏距離,并得出其鄰域集合。
# 計算T個鄰居
def cpt_W_Bi_T(moead):# 設置的鄰居個數錯誤(自己不能是自己的鄰居)if moead.T_size < 1:return -1# 計算權重的T_size 個鄰居for bi in range(moead.W.shape[0]):Bi = moead.W[bi]# 計算歐氏距離DIS = np.sum((moead.W - Bi) ** 2, axis=1)# 根據歐氏距離排序B_T = np.argsort(DIS)# 選取T_size+1個鄰居,+1是因為自己永遠是和自己歐氏距離最小的B_T = B_T[1:moead.T_size + 1]# 添加到集合moead.W_Bi_T.append(B_T)
? ? ? ? 除了計算鄰域,還需要使用目標函數計算種群的適應度,如下:
def Creat_Pop(moead):# 創建moead.Pop_size個種群Pop = []Pop_FV = []# 合法性檢查if moead.Pop_size < 1:print('error in creat_Pop')return -1# 構建集合while len(Pop) != moead.Pop_size:X = Creat_child(moead) # 創建一個個體Pop.append(X) # 將這個個體放入集合Pop_FV.append(moead.Test_fun.Func(X)) # 使用目標函數計算適應度moead.Pop, moead.Pop_FV = Pop, Pop_FV # 初始化主函數容器return Pop, Pop_FV
二、迭代
? ? ? ? ?在循環迭代中,對于個體pi的迭代主要分為三步:獲取鄰居;生成新解;更新種群。其具體流程如下面偽代碼所示:
for pi in range(0,len(moead.Pop)) # 遍歷集合Bi = moead.W_Bi_T[pi] # 加載pi號個體的鄰居集# 隨機抽取兩個鄰居個體ik = Bi[np.random.randint(moead.T_size)]il = Bi[np.random.randint(moead.T_size)]# 獲取x,xl,xk三個個體的值(目標個體本身和隨機抽取的兩個鄰居)Xi = moead.Pop[pi]Xk = moead.Pop[ik]xl = moead.Pop[il]# 使用上述三個個體生成新的解Y = generate_next(moead, gen, pi, Xi, Xk, Xl)cbxf_i = MOEAD_Utils.cpt_tchbycheff(moead, pi, Xi) # 計算進化前的切比雪夫距離cbxf_y = MOEAD_Utils.cpt_tchbycheff(moead, pi, Y) # 計算進化后的切比雪夫距離# 若進化后切比雪夫距離縮小就更新,否則保持原狀if cbxf_y < cbxf_i:F_Y = moead.Test_Fun.Func(Y)[:] # 計算進化后個體的適應度MOEAD_Utils.update_EP_By_ID(moead, pi, F_Y) # 更新pi號個體的值為YMOEAD_Utils.update_Z(moead, Y) # 更新理想點if abs(cbxf_y - cbxf_i) > d: # 進化幅度大于閾值MOEAD_Utils.update_EP_By_Y(moead, pi) # 更新支配前沿MOEAD_Utils.update_BTX(moead, Bi, Y) # 更新鄰域