Python 第二代非支配排序遗传算法(NSGA-II)求解多目标高次函数的帕累托前沿

2023-10-28

系列文章目录



前言

        在项目进度管理中,NSGA-II是常用的求解多目标项目进度管理优化问题的算法,虽然NSGA-III也出来了些日子,但是目前主流的研究MORCPSP问题的论文大多采用NSGA-II算法。我认为主要有三个原因:

        第一个是,NSGA-III算法需要更大的计算代价,因为它需要进行额外的种群初始化和排序操作来维护解的分布。这增加了算法的时间复杂度。第二就是,NSGA-III算法需要更多的参数设置,如分治桶的数量和邻域半径等。这些参数的不恰当设置可能会影响算法的性能。最后一点我觉得应该是,NSGA-III算法对目标函数的连续性和可微性有更高的要求。如果目标函数不满足这些条件,NSGA-III算法可能无法找到全局最优解。

        所以,在多目标资源受限问题上,NSGA-II算法仍然是一种更为通用和高效的解决方案,因为它具有更快的速度、更少的参数和对目标函数的较低要求。而我们在求解MORCPSP问题的时候,往往最追求的就是效率问题,即在短时间内求得问题的最优解(或近似最优解)。

        为了能吃透NSGA-II算法,为求解MORCPSP问题打基础,我这里先用NSGA-II求解一个常规的多目标高次函数的帕累托前沿。


一、模型的建立

        研究的模型为:min(y1=x^{2},x\in[0,10]), min(y2=(2-x)^{2},x\in[0,10])。 即求解两个目标函数最小值的问题。

二、算法的步骤

        1 设置参数,定义种群大小、进化代数、交叉概率、变异概率等

        2 定义一个自变量的类,这个类的属性值包括自变量x的值、目标函数值、非支配排序列表、拥挤度距离。

        3 通过random.uniform()函数初始化种群。

        4 迭代进化部分:

                4.1 计算目标函数的值

                4.2 进行非支配排序

                4.3 计算拥挤度距离

                4.4 依次变异、交叉、更新种群

        5 输出最优解集合并可视化展示出帕累托前沿离散图像

三、代码的实现

        代码如下:

import copy
import random
import matplotlib.pyplot as plt

# 设置参数
pop_size = 100  # 种群大小
gen_size = 500  # 进化代数
pc = 1  # 交叉概率
pm = 0.3  # 变异概率
num_obj = 2  # 目标函数个数
x_range = (-10, 10)  # 自变量取值范围


# 定义自变量的类
class Individual:
    def __init__(self, x):
        self.x = x
        self.objs = [None] * num_obj
        self.rank = None
        self.distance = 0.0

    # 计算目标函数的值
    def evaluate(self):
        self.objs[0] = self.x * self.x
        self.objs[1] = (2 - self.x) ** 2



# 初始化种群
pop = [Individual(random.uniform(*x_range)) for _ in range(pop_size)]

# 进化
for _ in range(gen_size):
    print(f"第{_}次迭代")
    # 计算目标函数的值
    for ind in pop:
        ind.evaluate()

    # 非支配排序
    fronts = [set()]
    for ind in pop:
        ind.domination_count = 0
        ind.dominated_set = set()

        for other in pop:
            if ind.objs[0] < other.objs[0] and ind.objs[1] < other.objs[1]:
                ind.dominated_set.add(other)
            elif ind.objs[0] > other.objs[0] and ind.objs[1] > other.objs[1]:
                ind.domination_count += 1

        if ind.domination_count == 0:
            ind.rank = 1
            fronts[0].add(ind)

    rank = 1
    while fronts[-1]:
        next_front = set()

        for ind in fronts[-1]:
            ind.rank = rank

            for dominated_ind in ind.dominated_set:
                dominated_ind.domination_count -= 1

                if dominated_ind.domination_count == 0:
                    next_front.add(dominated_ind)

        fronts.append(next_front)
        rank += 1

    # 计算拥挤度距离
    pop_for_cross=set()
    for front in fronts:
        if len(front) == 0:
            continue

        sorted_front = sorted(list(front), key=lambda ind: ind.rank)
        for i in range(num_obj):
            sorted_front[0].objs[i] = float('inf')
            sorted_front[-1].objs[i] = float('inf')
            for j in range(1, len(sorted_front) - 1):
                delta = sorted_front[j + 1].objs[i] - sorted_front[j - 1].objs[i]
                if delta == 0:
                    continue

                sorted_front[j].distance += delta / (x_range[1] - x_range[0])

        front_list = list(sorted_front)
        front_list.sort(key=lambda ind: (-ind.rank, -ind.distance))
        selected_inds =front_list
        if len(pop_for_cross) + len(selected_inds)<=pop_size:
            pop_for_cross.update(selected_inds)
        elif len(pop_for_cross)+len(selected_inds)>=pop_size and len(pop_for_cross)<pop_size:
            part_selected_inds=selected_inds[:(pop_size-len(pop_for_cross))]
            pop_for_cross.update(part_selected_inds)
            break
    # 交叉
    new_pop=set()
    # print(len(pop_for_cross))
    while len(new_pop) < len(pop_for_cross):
        x1, x2 = random.sample(pop_for_cross, 2)
        if random.random() < pc:
            new_x = (x1.x + x2.x) / 2
            delta_x = abs(x1.x - x2.x)
            new_x += delta_x * random.uniform(-1, 1)
            new_x = max(x_range[0], min(x_range[1], new_x))
            new_pop.add(Individual(new_x))

    # 变异
    for ind in new_pop:
        if random.random() < pm:
            delta_x = random.uniform(-1, 1) * (x_range[1] - x_range[0])
            ind.x += delta_x
            ind.x = max(x_range[0], min(x_range[1], ind.x))

    # 更新种群,把原来的精英(pop_for_cross)保留下来。即精英保留策略
    pop = list(new_pop)+list(pop_for_cross)

# 输出最优解集合
for ind in pop:
    ind.evaluate()

pareto_front = set()
for ind in pop:
    dominated = False
    for other in pop:
        if other.objs[0] < ind.objs[0] and other.objs[1] < ind.objs[1]:
            dominated = True
            break
    if not dominated:
        pareto_front.add(ind)

print("Pareto front:")
for ind in pareto_front:
    print(f"x={ind.x:.4f}, y1={ind.objs[0]:.4f}, y2={ind.objs[1]:.4f}")

# 可视化
plt.scatter([ind.objs[0] for ind in pop], [ind.objs[1] for ind in pop], c='gray', alpha=0.5)
plt.scatter([ind.objs[0] for ind in pareto_front], [ind.objs[1] for ind in pareto_front], c='r')
plt.xlabel('Objective 1')
plt.ylabel('Objective 2')
plt.show()

四、输出的结果

        分别输出了最优解(近似最优解)及帕累托前沿的离散图像:


总结

        程序每一次运行的结果可能都不一样,这也是像遗传算法这样的启发式算法的特性。此外,还可以考虑画一条种群的平均适应度函数值(最好归一化处理后)随着迭代次数变化的曲线,能够更加直观地展示迭代的梯度上升的过程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 第二代非支配排序遗传算法(NSGA-II)求解多目标高次函数的帕累托前沿 的相关文章

随机推荐

  • IBM MQ命令:DEFINE AUTHINFO

    此命令里有很多内容值得一看 https www ibm com docs en ibm mq 8 0 topic commands define authinfo q085490 6 一 CHCKCLNT CHCKCLNT This att
  • Git使用详解(结合GitLab和GitHub)

    转载请注明出处 https blog csdn net mythmayor article details 82346539 如果你想了解更多关于GitHub使用的问题 欢迎查看我的另一篇博客进行学习与交流 GitHub的使用详解 一 Gi
  • VC++读目录下所有文件

    include
  • ChatGPT训练营来啦,手把手带你玩转ChatGPT~

    ChatGPT的出现为测试行业带来了新的机遇和挑战 尽管许多人担心它的强大可能会取代测试人员 但实际上ChatGPT可以成为测试人员的强大助手 提高测试工作的效率和准确性 那么 我们应该如何借助 ChatGPT 让我们的测试工作更高效呢 C
  • Lua 随机数生成问题

    原文链接 http blog csdn net zhangxaochen article details 8095007 Lua 生成随机数需要用到两个函数 math randomseed xx math random n m 1 math
  • Win10开启热点共享后断网怎么解决?

    描述 关闭热点一切正常 打开热点以后电脑浏览器无法联网 最后发现可能是windows更新导致的 卸载了2022 06 17的更新就好了 因为没有去看dism 是什么东西 怕有木马啥的 就选择方法二卸载了2022 06 17的更新就好了 参考
  • QCustomPlot 使用——绘制折线图

    初始化数据 QVector
  • 检测模型设计准则

    作者 小书童 编辑 集智书童 点击下方卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心 目标检测 技术交流群 后台回复 2D检测综述 获取鱼眼检测 实时检测 通用2D检测等近5年内所有综述 设计高效 高质
  • 电路板布局

    一 PCB布局要求 1 可制造性设计 DFM 可装配性 DFA 可维修性 DFS 可测试性 DFT 2 电气性能实现 ccc fcc ce认证 EMC SI PI及散热要求 3 合理的成本 层数也多成本越高 4 美观度 二 布局的一般原则
  • uni封装ajax,uni-app封装ajax请求方法

    位置项目根目录index js 定义了两种请求get和post import baseconfig from common baseconfig js const httpClient request function method url
  • 求生之路2服务器搭建插件安装及详细的游戏参数配置教程windows

    求生之路2服务器搭建插件安装及详细的游戏参数配置教程windows 大家好我是艾西 最近研究了下 l4d2 求生之路2 这款游戏的搭建以及架设过程 今天就给喜欢l4d2这款游戏的小伙伴们分享下怎么搭建架设一个自己的服务器 毕竟自己当服主是热
  • C语言指针学习 课堂记录

    定义指针变量 类型名 指针变量名 pa和pb是自定义名 char pa 定义一个指向字符型的指针变量 int pb 定义一个指向整型的指针变量 取地址运算符和取值运算符 一 如果需要获取某个变量的内存地址 可以使用取地址运算符 char p
  • 如何获取虚函数表指针?虚函数表地址?虚函数地址?

    include
  • SOLIDWORKS PDM&Manage升级SOP——服务器篇

    SOLIDWORKS产品数据管理 PDM 解决方案可帮助您控制设计数据 并且从本质上改进您的团队就产品开发进行管理和协作的方式 使用 SOLIDWORKS PDM Professional 您的团队能够 1 安全地存储和索引设计数据以实现快
  • react 中常见API

    跟着大佬的步伐真好 参考 React进阶 React全部api解读 基础实践大全 夯实基础2万字总结
  • Java实现一个单号生成工具类

    在项目开发的过程中 如果一个系统存在多种不同类型的单据 单号生成就比较难以处理 为此 创造出一个单号生成的工具类就很有必要 直接上代码 实体类 数据库字段同下 public class SerialNumber TableId type I
  • python编程求三角形面积公式_python编程 输入三角形的三条边,计算三角形的面积\...

    展开全部 coding UTF 8 Filename test py author by www runoob com a float input 输入三角62616964757a686964616fe59b9ee7ad9431333433
  • 数据字典包括六个部分

    数据字典包括六个部分 数据字典要包括在以下六个部分吧 1 编写数据项 数据项描述 数据项名 数据项含义说明 别名 数据类型 长度 取值范围 取值含义 与其他数据项的逻辑关系 其中 取值范围 与其他数据项的逻辑关系 定义了数据的完整性约束条件
  • VirtualBox如何配置Bridge和Host-Only虚拟网卡

    VirtualBox安装OpenWRT虚拟机以后 需要为虚拟机配置两块虚拟网卡才能保证虚拟机的正常开发环境 一块设为Bridge模式 连接虚拟机网卡与Host网卡的Internet网络 另一块设为Host Only模式 用于Host主机访问
  • Python 第二代非支配排序遗传算法(NSGA-II)求解多目标高次函数的帕累托前沿

    系列文章目录 目录 系列文章目录 前言 一 模型的建立 二 算法的步骤 三 代码的实现 四 输出的结果 总结 前言 在项目进度管理中 NSGA II是常用的求解多目标项目进度管理优化问题的算法 虽然NSGA III也出来了些日子 但是目前主