多目标优化:以嵌套单目标粒子群实现(Python)

文章目录

  • 一、算法讲解
    • 粒子群
    • 复杂约束求解方法
    • 多目标优化
  • 二、将单目标算法 改为多目标


一、算法讲解

粒子群

见链接

粒子群算法求解无约束优化问题 源码实现
粒子群算法求解带约束优化问题 源码实现

复杂约束求解方法

优化算法求解复杂约束问题策略(以粒子群算法为例讲解求解复杂约束问题的多种策略)

多目标优化

NSGA2讲解
nsga2多目标优化之核心知识点(快速非支配排序、拥挤距离、精英选择策略)详解(python实现)
多目标遗传优化算法nsga2[python源码实现]

二、将单目标算法 改为多目标

多目标优化:以嵌套单目标粒子群实现(Python)_第1张图片
#!/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()

多目标优化:以嵌套单目标粒子群实现(Python)_第2张图片

讲解
多目标部分

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

作者:电气-余登武,禁止转载

你可能感兴趣的:(最优化实战例子,python)