遗传算法求解车间调度问题(附python代码)

背景介绍

车间调度问题(Job Shop Scheduling Problem, JSSP)是一类经典的组合优化问题,它在制造业和生产管理中有着广泛的应用。JSSP 的目标是对车间中的一系列作业进行排程,以使得作业在不同机器上的加工顺序是最优的,达到某种特定的优化目标,比如最小化总的作业完成时间(即使得总完工时间尽可能短),或者最小化延迟时间、最大化产量等。车间调度问题通常被描述为一系列作业集合 J 和一系列机器集合 M,每个作业由一系列操作组成,每个操作需要在特定的机器上加工一定时间。作业调度的规则如下:
(1)每个作业的操作需要按照特定的顺序进行。
(2)同一时刻,一台机器只能加工一个操作。
(3)操作一旦开始,在完成之前不能中断。
(4)所有作业的开始加工时间不得早于零。
(5)同一时刻,一个工件只能在一台机器上进行加工

车间调度问题可以被更进一步分类,如:
(a)开放式车间调度(Open Shop Scheduling):作业的操作可以在任意顺序进行。
(b)流水式车间调度(Flow Shop Scheduling):所有作业的操作必须按照相同的顺序进行。
(c)柔性车间调度(Flexible Job Shop Scheduling):每个操作可以在多台不同但功能相似的机器上加工。

车间调度问题是 NP-难问题,这意味着没有已知的多项式时间的算法可以保证找到每个实例的最优解。因此,对于实际应用中的车间调度问题,通常会运用启发式算法和元启发式算法来寻求近似的最优解,比如遗传算法、粒子群优化、蚁群算法和禁忌搜索等。

车间调度问题的研究对于提高生产效率、降低成本、提高企业的市场竞争力等都具有重要意义。在实际应用中,调度方案通常还需要考虑各种现实限制,例如机器故障、交货期限、工人的工作时间等。因此,车间调度问题在研究和工业领域都是一个非常活跃和挑战性的领域。
在这里插入图片描述

问题简介

如下表所示为某车间调度问题数据,该问题工包含5个工件,每个工件4道工序,共有6台机器,其中工序1只能由机器1完成,工序2可由机器2或机器4完成,工序3可由机器3或者机器5完成,工序4只能由机器6完成,表中数据为各工件的各项工序在机器上加工所需的时间。
在这里插入图片描述
上述问题可以描述成一个简单的柔性车间调度问题,问题包含以下基本假设:
(1) 同一时刻同一台机器只能加工一个工件。
(2) 每个工件在某一时刻只能在一台机器上加工,不能中断操作。
(3) 同一工件有先后顺序之分,不同工件则没有。
(4) 不同的工件具有相同的优先级。
(5)T=0时刻是开始时刻,此时所有工件尚未开始加工。
(6)所有工件的所有工序都要完成。

问题的目标函数是最小化完工时间,我们需要通过算法手段决策工件的工序在哪台机器上执行以及机器的具体执行顺序,下图为上述问题工序的加工顺序图。
在这里插入图片描述

算法介绍

本文拟采用遗传算法对该问题进行求解,实际上只要定义了编码、解码以及适应度函数,基本所有启发算法都可以代入使用,方便起见,本文选择相对简单的遗传算法来对该问题进行求解,着重介绍下编码、解码、适应度的计算以及交叉和变异。方便起见,下文提到的所有索引都从0开始,机器0代表机器1,机器1代表机器2,以此类推。
编码方式
通常来说,遗传算法中每个个体代表一个完整的解决方案,对于车间调度问题而言,若要表达完整的解决方案,编码中最少应该包含每个机器的加工工件以及加工顺序两部分信息。简单起见,本文的编码方式如下,工包含两部分信息,其中order部分为各机器的加工顺序信息,machine为各工件每道工序选择的加工机器信息。

								{'order': [[2, 1, 4, 0, 3],[4, 3, 1, 0, 2],[0, 1, 4, 2, 3],[1, 2, 0, 4, 3],[2, 1, 4, 0, 3],[1, 2, 4, 0, 3]],'machine': [[0, 1, 4, 5],[0, 1, 4, 5],[0, 3, 4, 5],[0, 3, 4, 5],[0, 3, 2, 5]]}

例如其中[2, 1, 4, 0, 3]表示第一台机器的加工顺序为2->1->4->0->3,以此类推,后面的5个list分别为其余5台机器的加工顺序。看到这里可能会有疑问,前面不是提到了某些工序只需要在多台机器中的任意一台进行加工即可吗?order中的信息看起来所有工件都会在所有机器上进行加工?machine中的信息就是用于解决这个问题的,machine的长度为5,代表5个工件的使用机器情况,例如[0,1,4,5]表示工件0的四道工序分别在机器0、1、4、5上进行加工。

解码方式
以编码方式中提到的个体为例,由于工序0只有一台机器,因此机器0的加工顺序为[[2, 1, 4, 0, 3],工序2的可加工机器为1和3,从machine信息中可以看出来,使用机器1加工的是[0,1],使用机器3加工的是[2,3,4],再结合order中的顺序,可以得到每台机器上加工的工件及其加工顺序为:

			[[2, 1, 4, 0, 3], [1, 0], [4], [2, 4, 3], [2, 1, 0, 3], [1, 2, 4, 0, 3]]

以第一台机器为例,可以计算出每个工件的开始及结束加工时间如下,其中t1为开始加工时间,t2为结束加工时间。

							{2: {'t1': 0, 't2': 5},1: {'t1': 5, 't2': 14},4: {'t1': 14, 't2': 20},0: {'t1': 20, 't2': 27},3: {'t1': 27, 't2': 38}}

同理,可以获得其余每台机器上的加工时间,用如下所示的字典表示,其中第一个key为工序编号,第2个key为机器编号,第3个key为工件编号,例如time_table[0][0][2]={‘t1’: 0, ‘t2’: 5}表示第一道工序,工件2在机器0上进行加工,开始时间是0,结束时间是5。

								{0: {0: {2: {'t1': 0, 't2': 5},1: {'t1': 5, 't2': 14},4: {'t1': 14, 't2': 20},0: {'t1': 20, 't2': 27},3: {'t1': 27, 't2': 38}}},1: {1: {1: {'t1': 14, 't2': 20}, 0: {'t1': 27, 't2': 32}},3: {2: {'t1': 5, 't2': 11},4: {'t1': 20, 't2': 33},3: {'t1': 38, 't2': 48}}},2: {2: {4: {'t1': 33, 't2': 44}},4: {2: {'t1': 11, 't2': 20},1: {'t1': 20, 't2': 31},0: {'t1': 32, 't2': 39},3: {'t1': 48, 't2': 56}}},3: {5: {1: {'t1': 31, 't2': 37},2: {'t1': 37, 't2': 45},4: {'t1': 45, 't2': 54},0: {'t1': 54, 't2': 61},3: {'t1': 61, 't2': 71}}}}

适应度计算
在上一节解码过程中,我们首先根据order和machine的信息获得了每台机器上加工的工件以及具体的加工顺序,然后按照离散时间仿真的思路(略复杂)能够获得每个工件的在每道工序的具体加工时间以及结束时间及其对应的机器,那么最大完工时间只需要在上述time table取所有工件的最大t2即可,我们定义适应度为最大完工时间的倒数,这样适应度永远大于0,且适应度越大,最大完工时间越短。

种群交叉
交叉方式分为两部分,第一部分是order部分的交叉,第二部分是machine部分的交叉将父代和母代的加工顺序组合分配给子代,例如假设父代和母代的order信息如下:

									父代:[[2, 1, 4, 0, 3],[4, 3, 1, 0, 2],[0, 1, 4, 2, 3],[1, 2, 0, 4, 3],[2, 1, 4, 0, 3],[1, 2, 4, 0, 3]]母代:[[1, 2, 3, 0, 4],[3, 4, 2, 0, 1],[1, 0, 2, 4, 3],[2, 1, 3, 0, 4],[2, 1, 4, 3, 0],[3, 1, 4, 0, 2]]

相当于父代和母代总共有12个排列顺序,随机选择6个分配给孩子1,随机选择6个分配给孩子2,可以获得如下两个子代,第二部分是machine的交叉,过程与第一部分类似。

									子代1:[[2, 1, 4, 0, 3],[4, 3, 1, 0, 2],[0, 1, 4, 2, 3],[2, 1, 3, 0, 4],[2, 1, 4, 3, 0],[3, 1, 4, 0, 2]]子代2:[[1, 2, 3, 0, 4],[3, 4, 2, 0, 1],[1, 0, 2, 4, 3],[1, 2, 0, 4, 3],[2, 1, 4, 0, 3],[1, 2, 4, 0, 3]]

个体变异
变异也有两种情况,第一种是order部分的变异,一部分是machine部分的变异。首先并非所有个体都要参与变异,一般有一个变异参数,对于交叉生成的个体,如果生成的随机数小于这个参数则进行变异。order部分的变异首先生成一个随机数n,该随机数指定order要变异的次数,其次生成3n个随机数,每3个为一组,例如生成的随机数是1,2,3表示对机器1的加工顺序2和加工顺序3进行调换,例如n=1,且生成的随机数为0、0、1,那么子代1将变为:

									子代1:[[1, 2, 4, 0, 3],[4, 3, 1, 0, 2],[0, 1, 4, 2, 3],[2, 1, 3, 0, 4],[2, 1, 4, 3, 0],[3, 1, 4, 0, 2]]

接下来是machine的变异,machine的变异首先生成一个随机数m,表示machine部分进行变异的次数,其次生成2m个随机数,每2为一组,例如生成的随机数2,1,子代的machine从子代a变成子代b,工件2的工序1使用的机器由3变为1。

							子代a: [[0, 1, 4, 5],[0, 1, 4, 5],[0, 3, 4, 5],[0, 3, 4, 5],[0, 3, 2, 5]]子代b:[[0, 1, 4, 5],[0, 1, 4, 5],[0, 1, 4, 5],[0, 3, 4, 5],[0, 3, 2, 5]]

代码实现

数据处理

# 工件数量
workpiece_num=5# 工序数量
process_num=4# 机器数量
machine_num=6# 加工时间
process_time_dict={}
process_time_dict[0]=[7,5,9,9,7,7]
process_time_dict[1]=[9,6,8,8,11,6]
process_time_dict[2]=[5,8,6,6,9,8]
process_time_dict[3]=[11,12,12,10,8,10]
process_time_dict[4]=[6,9,11,13,9,9]# 工序对应的机器
process_machin_dict={0:[0],1:[1,3],2:[2,4],3:[5]}

种群交叉

'''
种群交叉
'''
def cross(father,mother):child1={}child2={}order1=[]order2=[]for i in range(machine_num):if randint(0,1):order1.append(father['order'][i])order2.append(mother['order'][i])else:order1.append(mother['order'][i])order2.append(father['order'][i])child1['order']=order1child2['order']=order2machine1=[]machine2=[]for j in range(workpiece_num):if randint(0,1):machine1.append(father['machine'][j])machine2.append(mother['machine'][j])else:machine1.append(mother['machine'][j])machine2.append(father['machine'][j])child1['machine']=machine1child2['machine']=machine2return child1,child2

个体变异

'''
个体变异
'''
def mutate(solution):solution_copy=deepcopy(solution)# order调整swap_num=randint(0,machine_num)for i in range(swap_num):idx=randint(0,machine_num-1)s1,s2=randint(0,workpiece_num-1),randint(0,workpiece_num-1)temp=solution_copy['order'][idx][s1]solution_copy['order'][idx][s1]=solution_copy['order'][idx][s2]solution_copy['order'][idx][s2]=temp# machine调整change_num=randint(0,workpiece_num)for j in range(change_num):idx=randint(0,process_num-1)solution_copy['machine'][j][idx]=random.choice(process_machin_dict[idx])if get_fitness(solution_copy)>get_fitness(solution):return solution_copyreturn solution

可视化

'''
绘制甘特图
'''
def plot_gantt(solution):# 给定的数据time_table,machine_order=resolve_solution(deepcopy(solution))data={}for k in time_table:for i in time_table[k]:data[i]=time_table[k][i]# 创建颜色绘图colors = list(mcolors.TABLEAU_COLORS.keys())  # 预定义的颜色color_map = {}fig, ax = plt.subplots(figsize=[20,10])for machine, jobs in data.items():for job, times in jobs.items():start_time = times['t1']end_time = times['t2']duration = end_time - start_time# 检查工件是否已经分配了颜色if job not in color_map:color_map[job] = colors.pop(0)# 绘制甘特图的条形块ax.broken_barh([(start_time, duration)], (machine - 0.4, 0.8), facecolors=color_map[job])# 设置y轴ax.set_yticks(range(len(data)))ax.set_yticklabels(['Machine ' + str(i) for i in range(machine_num)])# 设置x轴ax.set_xlabel('Time')ax.set_xlim(0, max(time['t2'] for machine in data.values() for time in machine.values()))# 绘制图例patches = [plt.Rectangle((0,0),1,1, color=mcolors.TABLEAU_COLORS[color]) for color in color_map.values()]labels = [f'Workpiece {i}' for i in color_map.keys()]ax.legend(patches, labels, loc='upper right')# 在条形上添加任务编号for machine, jobs in data.items():for job, times in jobs.items():start_time = times['t1']duration = times['t2'] - times['t1']ax.text(x=start_time + duration/2, y=machine, s=f'{job}', color='white', va='center', ha='center',bbox=dict(boxstyle='round,pad=0.1', facecolor=color_map[job], edgecolor='none'))# 显示网格ax.grid(False)# 展示图表plt.show()

结果展示

收敛过程
在这里插入图片描述

甘特图
在这里插入图片描述

本文小结

本文对车间调度问题进行了简单介绍,并以一个简单柔性车间调度问题为例,使用遗传算法对该问题进行了求解,并且详细描述了使用遗传算法求解过程中的编码、解码、交叉以及变异等操作。另外,本文给出了遗传算法求解车间调度问题的主体python代码,最后展示了算法求解的结果,包括结果收敛过程以及甘特图,验证了算法的有效性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

万相台的功能是什么?如何使用万相台?

1.特点: 万相台是一个智能渠道,可控性弱,高转化,人群&关键词是黑盒; 2.场景多: 有拉新快、活动加速、上新快、货品加速、活动加速、多目标直投、全站推等; 3.扣费逻辑:cpc付…

Sm4【国密4加密解密】

当我们开发金融、国企、政府信息系统时,不仅要符合网络安全的等保二级、等保三级,还要求符合国密的安全要求,等保测评已经实行很久了,而国密测评近两年才刚开始。那什么是密码/国密?什么是密评?本文就关于密…

Linux:线程概念 线程控制

Linux:线程概念 & 线程控制 线程概念轻量级进程 LWP页表 线程控制POSIX 线程库 - ptherad线程创建pthread_createpthread_self 线程退出pthread_exitpthread_cancelpthread_joinpthread_detach 线程架构线程与地址空间线程与pthread动态库 线程的优缺点 线程概念…

机器学习与数据挖掘知识点总结(二)分类算法

目录 1、什么是数据挖掘 2、为什么要有数据挖掘 3、数据挖掘用在分类任务中的算法 朴素贝叶斯算法 svm支持向量机算法 PCA主成分分析算法 k-means算法 决策树 1、什么是数据挖掘 数据挖掘是从大量数据中发现隐藏在其中的模式、关系和规律的过程。它利用统计学、机器学…

14.shell awk数组

awk数组 awk数组awk数组示例Nginx日志分析 awk数组 1.什么是awk数组 数组其实也算是变量,传统的变量只能存储一个值,但数组可以存储多个值 2.awk数组应用场景 通常用来统计、比如:统计网站访问TOP10、网站url访问TOP10等等 3.awk数组统计技巧 1.在awk中,使用数组时,不仅可以…

Interview preparation--RabbitMQ

AMQP AMQP(Advanced Message Queueing protocol). 高级消息队列协议,是进程之间床底一步新消息的网络协议AMQP工作原理如下: 发布者(Publisher)发布消息(Message)经过交换机(Exchange&#xff…

新视窗新一代物业管理系统 GetCertificateInfoByStudentId SQL注入漏洞复现

0x01 产品简介 新视窗物业管理系统属于专家型的物业管理软件,能够给物业公司内部管理提供全面的解决方案,具有房产管理、客户管理、租赁管理、仪表管理、财务收费、发票管理、合同管理、仓储管理、设施设备管理、客户服务管理、会员管理、人事管理、资产管理、日常办公、档案…

HTML+CSS 动态卡片

效果演示 实现了一个带有动态背景和图片放大效果的卡片展示。卡片的背景是由两种颜色交替组成的斜线条纹&#xff0c;同时背景会以一定速度循环滚动。当鼠标悬停在卡片上时&#xff0c;卡片的图片会放大&#xff0c;并且卡片的背景会变为彩色。 Code HTML <!DOCTYPE html&…

简单聊一下Oracle,MySQL,postgresql三种锁表的机制,行锁和表锁

MySQL&#xff1a; MySQL使用行级锁定和表级锁定。行级锁定允许多个会话同时写入表&#xff0c;适用于多用户、高并发和OLTP应用。表级锁定只允许一个会话一次更新表&#xff0c;适用于只读、主要读取或单用户应用。 比如mysql开启一个窗口执行 begin; update xc_county_a…

【STM32】飞控设计

【一些入门知识】 1.飞行原理 【垂直运动】 当 mg&#xff1e;F1F2F3F4&#xff0c;此时做下降加速飞行 当 mg&#xff1c;F1F2F3F4&#xff0c;此时做升高加速飞行 当 mgF1F2F3F4 &#xff0c;此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…

我的考研经历

当我写下这篇文章时&#xff0c;我已经从考研 的失败中走出来了&#xff0c;考研的整个过程都写在博客日志里面了&#xff0c;在整理并阅读考研的日志时&#xff0c;想写下一篇总结&#xff0c;也算是为了更好的吸取教训。 前期日志模板&#xff1a;时间安排的还算紧凑&#x…

【启明智显分享】Model系列工业级HMI芯片:开源RISC-V+RTOS实时系统,开放!高效!

前言 「Model系列」芯片是启明智显针对工业、行业以及车载产品市场推出的系列HMI芯片&#xff0c;主要应用于工业自动化、智能终端HMI、车载仪表盘、两轮车彩屏仪表、串口屏、智能中控、智能家居、充电桩显示屏、储能显示屏、工业触摸屏等领域。此系列具有高性能、低成本的特点…

C4D如何预览动画?C4D动画云渲染助力

C4D是一款功能丰富的3D设计软件&#xff0c;以其快速的预览渲染和多样的渲染插件而闻名&#xff0c;其卓越的渲染效果赢得了CG行业专业人士的广泛赞誉。尽管C4D的渲染功能十分强大&#xff0c;但对于初学者而言&#xff0c;其复杂的渲染设置可能会带来一些挑战。本文一起来看看…

最好用的邮箱管理软件推荐,邮箱管理软件哪个好?(干货篇)

在快节奏的工作与生活中&#xff0c;有效管理电子邮件成为提升个人与团队效率的关键。 面对海量信息流&#xff0c;一款好的邮箱管理软件不仅能够帮助我们高效地整理收件箱&#xff0c;还能确保重要邮件不会错过&#xff0c;同时提升通讯的便捷性和安全性。 本文将为您推荐几款…

Http协议JSON格式

1. 计算机网络 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络管理软件及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计算机系统。 思考:计算机网络…

【第三篇】SpringSecurity请求流程分析

简介 本篇文章主要分析一下SpringSecurity在系统启动的时候做了那些事情、第一次请求执行的流程是什么、以及SpringSecurity的认证流程是怎么样的,主要的过滤器有哪些? SpringSecurity初始化流程 1.加载配置文件web.xml 当Web服务启动的时候,会加载我们配置的web.xml文件…

【记录与感想】CS61b-21sp project0(2048游戏)

项目概述 本项目是cs61b课程开课以来的第一个项目&#xff0c;游戏本身非常简单。它在 44 的方格网格上进行&#xff0c;每个方格可以是空的&#xff0c;也可以包含一个带有整数&#xff08;大于或等于 2 的 2 的幂&#xff09;的图块。在第一步之前&#xff0c;应用程序会将一…

Python第二语言(十四、高阶基础)

目录 1. 闭包 1.1 使用闭包注意事项 1.2 小结 2. 装饰器&#xff1a;实际上也是一种闭包&#xff1b; 2.1 装饰器的写法&#xff08;闭包写法&#xff09; &#xff1a;基础写法&#xff0c;只是解释装饰器是怎么写的&#xff1b; 2.2 装饰器的语法糖写法&#xff1a;函数…

半导体笔记汇总

半导体笔记汇总 介于导体与绝缘体之间的材质就叫做半导体。半导体器件主要分三类&#xff1a;二极管、三极管、MOS管。 一、半导体理论基础 1、导体、半导体和绝缘体 我们根据物质的导电性能强弱将物质分为导体、半导体和绝缘体。电导率与电阻率互为倒数&#xff0c;下图中…

3d模型文件格式有那些,什么区别?---模大狮模型网

3D模型文件格式有很多种&#xff0c;每种格式都有其特点和应用场景。常见的3D模型文件格式包括OBJ、FBX、STL、3DS、DAE等&#xff0c;下面将逐一介绍这些格式的区别。 1. OBJ格式&#xff1a;OBJ是一种开放的3D模型文件格式&#xff0c;可以被几乎所有的3D软件所支持。OBJ格式…