见链接
粒子群算法求解无约束优化问题 源码实现
粒子群算法求解带约束优化问题 源码实现
优化算法求解复杂约束问题策略(以粒子群算法为例讲解求解复杂约束问题的多种策略)
NSGA2讲解
nsga2多目标优化之核心知识点(快速非支配排序、拥挤距离、精英选择策略)详解(python实现)
多目标遗传优化算法nsga2[python源码实现]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: yudengwu(余登武)
# @Date : 2023/1/2
# @email:[email protected]
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
import matplotlib;
matplotlib.use('TkAgg')
from tqdm import tqdm # 进度条设置
class Liqun:
def __init__(self, A1, A2):
self.A1 = A1 # 目标函数1权重
self.A2 = A2 # 目标函数2权重
self.e1 = 0.1 # 可接受的惩罚项
self.min_xy = [1, -1] # 范围 下限, x下限1,y下限-1 (两个目标函数的x,y上下限范围不一样,上下限应取它们的交集
self.max_xy = [2, 0] # 范围上限 x上限2,y上限0
self.w = 1 # 惯性因子,一般取1
self.c1 = 2 # 学习因子1,一般取2
self.c2 = 2 # 学习因子2,一般取2
self.dim = 2 # 变量个数 X维度2个
self.NP = 300 # 种群大小,即种群中小鸟的个数
self.iter_num = 100 # 算法最大迭代次数
self.max_vel = 0.5 # 限制粒子的最大速度为0.5
self.min_vel = -0.5 # 限制粒子的最小速度为-0.5
# ==========定义两个目标函数、和对应的惩罚项=============
# 定义函数1
def calc_f1(self, X1):
"""
个体目标函数
:param X1: 十进制格式 X1[0]=x,X1[1]=y
:return: 函数1值
"""
x = X1[0]
y = X1[1]
pi = np.pi
return 2 + x ** 2 - np.cos(2 * pi * x) + y ** 2 - np.cos(2 * 3.14 * y)
# 定义函数2
def calc_f2(self, X1):
"""
个体目标函数
:param X1: 十进制格式 X1[0]=x,X1[0]=y
:return: 函数2值
"""
x = X1[0]
y = X1[1]
return (x ** 2 + y + 1)
# 本例子中,惩罚项不起作用,因为在个体初始化、进化过程中,只选择对的 惩罚项写在这里,只是为了通用模板
# 函数1 对应的约束 (上下限约束,放到二进制转十进制哪里)
def calc_e1(self, X1):
"""
函数1 对应的个体惩罚项
:param X1: 十进制格式 X1[0]=x,X1[0]=y
:return:
"""
x = X1[0]
y = X1[1]
sumcost = []
"""计算第一个约束的惩罚项"""
e1 = x + y - 6 # x+y<=6
sumcost.append(max(0, e1))
"""计算第二个约束的惩罚项"""
e2 = 3 * x - 2 * y - 5 # 3x-2y<=5
sumcost.append(max(0, e2))
return np.sum(sumcost)
# 函数2 对应的约束 (上下限约束,放到二进制转十进制哪里)
def calc_e2(self, X1):
"""
函数2 对应的个体惩罚项
:param X1: 十进制格式 X1[0]=x,X1[0]=y
:return:
"""
x = X1[0]
y = X1[1]
sumcost = []
"""计算第一个约束的惩罚项"""
e1 = x + y - 5 # x+y<=5
sumcost.append(max(0, e1))
"""计算第二个约束的惩罚项"""
e2 = 2 * x - 3 * y - 4 # 2x-3y<=4
sumcost.append(max(0, e2))
return np.sum(sumcost)
# ===初始化种群====
def Initialize(self):
"""
:return: 十进制格式 2维
"""
X = np.zeros(shape=(self.NP, 2)) #
for i in range(self.NP): # 遍历各个粒子
# 上下限约束
X[i, 0] = np.random.uniform(self.min_xy[0], self.max_xy[0], 1)[0] # X
X[i, 1] = np.random.uniform(self.min_xy[1], self.max_xy[1], 1)[0] # y
# 不等式约束
while ((X[i, 0] + X[i, 1]) > 6) or ((3 * X[i, 0] - 2 * X[i, 1]) > 5) or (
(X[i, 0] + X[i, 1]) > 5) or ((2 * X[i, 0] - 3 * X[i, 1]) > 4):
X[i, 0] = np.random.uniform(self.min_xy[0], self.max_xy[0], 1)[0] # X
X[i, 1] = np.random.uniform(self.min_xy[1], self.max_xy[1], 1)[0] # y
return X
# ===粒子群速度更新公式====
def velocity_update(self, V, X, pbest, gbest):
"""
根据速度更新公式更新每个粒子的速度
种群size
:param V: 粒子当前的速度矩阵,NP*dim的矩阵
:param X: 粒子当前的位置矩阵,NP*dim*的矩阵
:param pbest: 每个粒子历史最优位置,NP*dim 的矩阵
:param gbest: 种群历史最优位置,1*dim 的矩阵
"""
r1 = np.random.random((self.NP, 2))
r2 = np.random.random((self.NP, 2))
V = self.w * V + self.c1 * r1 * (pbest - X) + self.c2 * r2 * (gbest - X) # 直接对照公式写就好了
# 防止越界处理
V[V < self.max_vel] = self.max_vel
V[V > self.min_vel] = self.min_vel
return V
# ===粒子群位置更新公式====
def position_update(self, X, V):
"""
根据公式更新粒子的位置
:param X: 粒子当前的位置矩阵,维度是 NP*dim*24
:param V: 粒子当前的速度举着,维度是 NP*dim*24
"""
X = X + V # 更新位置
for i in range(self.NP): # 遍历各个粒子
# 上下限约束
if X[i, 0] < self.min_xy[0] or X[i, 0] > self.max_xy[0]:
X[i, 0] = np.random.uniform(self.min_xy[0], self.max_xy[0], 1)[0] # X
if X[i, 1] < self.min_xy[1] or X[i, 1] > self.max_xy[1]:
X[i, 1] = np.random.uniform(self.min_xy[1], self.max_xy[1], 1)[0] # y
# 不等式约束
while ((X[i, 0] + X[i, 1]) > 6) or ((3 * X[i, 0] - 2 * X[i, 1]) > 5) or (
(X[i, 0] + X[i, 1]) > 5) or ((2 * X[i, 0] - 3 * X[i, 1]) > 4):
X[i, 0] = np.random.uniform(self.min_xy[0], self.max_xy[0], 1)[0] # X
X[i, 1] = np.random.uniform(self.min_xy[1], self.max_xy[1], 1)[0] # y
return X
# 更新种群函数
def update_best(self, pbest, pbest_fitness, pbest_e, xi, xi_fitness, xi_e):
"""
判断是否需要更新粒子的历史最优位置
:param pbest: 历史最优位置
:param pbest_fitness: 历史最优位置对应的适应度值
:param pbest_e: 历史最优位置对应的约束惩罚项
:param xi: 当前位置
:param xi_fitness: 当前位置的适应度函数值
:param xi_e: 当前位置的约束惩罚项
:return:
"""
# 下面的 self.e1 是考虑到计算机的数值精度位置,不同问题设置不同的可接受值
# 规则1,如果 pbest 和 xi 都没有违反约束,则取适应度小的
if pbest_e <= self.e1 and xi_e <= self.e1:
if pbest_fitness <= xi_fitness:
return pbest, pbest_fitness, pbest_e
else:
return xi, xi_fitness, xi_e
# 规则2,如果当前位置违反约束而历史最优没有违反约束,则取历史最优
if pbest_e < self.e1 and xi_e >= self.e1:
return pbest, pbest_fitness, pbest_e
# 规则3,如果历史位置违反约束而当前位置没有违反约束,则取当前位置
if pbest_e >= self.e1 and xi_e < self.e1:
return xi, xi_fitness, xi_e
# 规则4,如果两个都违反约束,则取适应度值小的
if pbest_fitness <= xi_fitness:
return pbest, pbest_fitness, pbest_e
else:
return xi, xi_fitness, xi_e
def main(self):
best_fitness = [] # 记录每次迭代的效果
best_X = [] # 存放最优个体
X = self.Initialize() # 初始化群体
VX = np.random.random(size=(X.shape)) # 速度
fitness = np.zeros((self.NP, 1)) # 存放父辈适应度值
ee = np.zeros((self.NP, 1)) # 存放父辈惩罚项值
# ===计算父辈适应度。惩罚项===
for j in range(self.NP): # 遍历每一个粒子
fitness[j] = self.A1 * self.calc_f1(X[j]) + self.A2 * self.calc_f2(X[j]) # 目标函数值
ee[j] = self.A1 * self.calc_e1(X[j]) + self.A2 * self.calc_e2(X[j]) # 惩罚项
parentfitness = fitness + ee # 计算适应度值 适应度值=目标函数值+惩罚项
# 历史最优
Pbestfitness = parentfitness # 粒子历史最优位置对应的适应度值#(NP, 1
Pbeste = ee # 粒子历史最优位置对应的惩罚项和 parentee
pbestX = X # 个体最优X (NP, 2)
# 全局最优
gbest_i = Pbestfitness.argmin() # 全局最优对应的粒子编号
gbestX = X[gbest_i] # 全局最优X
gbestfitness = Pbestfitness[gbest_i] # 全局最优适应度值
gbeste = Pbeste[gbest_i] # 全局最优对应的惩罚项和
for j in tqdm(range(self.iter_num)): # 遍历每一次迭代
Pbestfitness = Pbestfitness.copy() # 必须加,不然会被篡改值,造成结果错
Pbeste = Pbeste.copy() # 必须加,不然会被篡改值,造成结果错
pbestX = pbestX.copy() # 必须加,不然会被篡改值,造成结果错
gbestX = gbestX.copy() # 必须加,不然会被篡改值,造成结果错
gbestfitness = gbestfitness.copy() # 必须加,不然会被篡改值,造成结果错
gbeste = gbeste.copy() # 必须加,不然会被篡改值,造成结果错
# 速度更新
VX = self.velocity_update(VX, X, pbestX, gbestX) # 速度更新
# 位置更新
X = self.position_update(X, VX)
# 计算每个粒子的目标函数和约束惩罚项
childfit = np.zeros((self.NP, 1)) # 目标函数值
childee = np.zeros((self.NP, 1)) # 惩罚项
for j in range(self.NP): # 遍历每一个粒子
childfit[j] = self.A1 * self.calc_f1(X[j]) + self.A2 * self.calc_f2(X[j]) # 目标函数值
childee[j] = self.A1 * self.calc_e1(X[j]) + self.A2 * self.calc_e2(X[j]) # 惩罚项 # 惩罚项
childfitness = childfit + childee # 子代适应度值
# 更新个体最优
for i in range(self.NP):
pbestxi = pbestX[i] # #个体最优X
pbest_fitnessi = Pbestfitness[i] # 个体最优适应度
pbest_ei = Pbeste[i] # 个体最优惩罚项
# 计算更新个体历史最优
pbestX1, pbestfitness1, pbest_e1 = self.update_best(pbestxi, pbest_fitnessi, pbest_ei, X[i],
childfit[i], childee[i])
pbestX[i] = pbestX1
Pbestfitness[i] = pbestfitness1
Pbeste[i] = pbest_e1
# 更新全局最优
for i in range(self.NP):
gbestX, gbestfitness, gbeste = self.update_best(gbestX, gbestfitness, gbeste,
pbestX[i], Pbestfitness[i],
Pbeste[i])
best_fitness.append(gbestfitness) # 记录全局最优
return self.calc_f1(gbestX), self.calc_f2(gbestX), gbestX
def main():
A1 = np.around(np.arange(0, 1.2, 0.2), 2)
A2 = np.around(np.arange(1, -0.2, -0.2), 2)
Values = np.zeros(shape=(len(A1), 2))
for i in range(len(A1)):
a1 = A1[i]
a2 = A2[i]
print("a1, a2:", a1, a2)
li = Liqun(a1, a2)
value1, value2, gbestX = li.main()
print("gbestX:", gbestX)
Values[i, 0] = value1
Values[i, 1] = value2
arrSortedIndex = np.lexsort((Values[:, 1], Values[:, 0])) # 排序(先按函数2大小排,再按函数1大小排)
Values = Values[arrSortedIndex]
plt.plot(Values[:, 0], Values[:, 1])
plt.xlabel("函数1")
plt.ylabel("函数2")
plt.show()
if __name__ == "__main__":
main()
讲解
多目标部分
def main():
A1=np.around(np.arange(0,1.2,0.2),2)
A2=np.around(np.arange(1,-0.2,-0.2),2)
Values=np.zeros(shape=(len(A1),2))
for i in range(len(A1)):
a1=A1[i]
a2 = A2[i]
print("a1, a2:",a1,a2)
li = Liqun(a1, a2)
value1, value2,gbestX = li.main()
print("gbestX:",gbestX)
Values[i, 0] = value1
Values[i, 1] = value2
作者:电气-余登武,禁止转载