车间调度系列文章:

  • 1、车间调度历史文章
  • 2、书本算法重现丨遗传算法:以算例MK01为例

引言

算法重现系列文章,都是对书本《柔性作业车间调度智能算法及其应用》一书的算法实现,该书作者:高亮、张国辉、王晓娟。具体电子书:可关注公众号后,回复:调度,获得。

问题描述

柔性车间调度问题可描述为:多个工件在多台机器上加工,工件安排加工时严格按照工序的先后顺序,至少有一道工序有多个可加工机器,在某些优化目标下安排生产。柔性车间调度问题的约束条件如下:

  • (1)同一台机器同一时刻只能加工一个工件;
  • (2)同一工件的同一道工序在同一时刻被加工的机器数是一;
  • (3)任意工序开始加工不能中断;
  • (4)各个工件之间不存在的优先级的差别;
  • (5)同一工件的工序之间存在先后约束,不同工件的工序之间不存在先后约束;
  • (6)所有工件在零时刻都可以被加工。

MK01算例:

10 6 2
6 2 1 5 3 4 3 5 3 3 5 2 1 2 3 4 6 2 3 6 5 2 6 1 1 1 3 1 3 6 6 3 6 4 3
5 1 2 6 1 3 1 1 1 2 2 2 6 4 6 3 6 5 2 6 1 1
5 1 2 6 2 3 4 6 2 3 6 5 2 6 1 1 3 3 4 2 6 6 6 2 1 1 5 5
5 3 6 5 2 6 1 1 1 2 6 1 3 1 3 5 3 3 5 2 1 2 3 4 6 2
6 3 5 3 3 5 2 1 3 6 5 2 6 1 1 1 2 6 2 1 5 3 4 2 2 6 4 6 3 3 4 2 6 6 6
6 2 3 4 6 2 1 1 2 3 3 4 2 6 6 6 1 2 6 3 6 5 2 6 1 1 2 1 3 4 2
5 1 6 1 2 1 3 4 2 3 3 4 2 6 6 6 3 2 6 5 1 1 6 1 3 1
5 2 3 4 6 2 3 3 4 2 6 6 6 3 6 5 2 6 1 1 1 2 6 2 2 6 4 6
6 1 6 1 2 1 1 5 5 3 6 6 3 6 4 3 1 1 2 3 3 4 2 6 6 6 2 2 6 4 6
6 2 3 4 6 2 3 3 4 2 6 6 6 3 5 3 3 5 2 1 1 6 1 2 2 6 4 6 2 1 3 4 2

第一行的10,6是工件数和机器数。

第二行第一个加粗的数字6表示,工件1有6道工序。斜体的2 1 5 3 4,表示工件1的第一道工序有两个可选机器,分别是1和3,加工时间是5和4,后面的3 5 3 3 5 2 1表示工件1的第二道工序有3个可选机器,分别是5,3,2,加工时间是3,5,1,一行就是1个工件的所有工序的可选机器可加工时间,后面的工序以此类推。

下面的每一行以此类推。本系列算例MK01.txt数据文件可在gitee仓库下载:

https://gitee.com/XZDNF-1618/data.git

数学模型

字符说明:

目标函数:

约束条件:

柔性作业车间工具

本文写了甘特图的画图函数;工序,机器,加工时间编码的生成函数;编码的解码函数。甘特图和解码前面推文有介绍,为了能在遗传算法使用,下面介绍一下编码的生成:

  • 步骤1:按照工件的工序数依次生成工序编码如下:

work = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9]

程序里为方便运算,0表示工件1,依次类推。

  • 步骤2:随机打乱work得到如下编码:

job= [7, 1, 7, 9, 4, 6, 4, 2, 4, 6, 5, 0, 5, 1, 1, 5, 1, 6, 3, 2, 4, 9, 2, 3, 8, 8, 4, 0, 0, 7, 7, 6, 1, 8, 9, 0, 2, 9, 3, 6, 8, 7, 5, 8, 9, 9, 3, 4, 3, 2, 5, 5, 0, 0, 8]

job就是一个可行工序编码。

代码在fjsp.py里。

机器和加工时间编码:

参考文献的3种机器编码生成方法:全局选择、局部选择和随机选择。

对于6个加工机器的mk01。

全局选择:依次安排每个工件的加工,每道工序选择最小负荷的机器。

局部选择:依次安排每个工件的加工,每次安排完一个工件加工后,各个机器的负荷清0,每道工序选择最小负荷的机器。

随机选择:依次安排每个工件的加工,每道工序随机选择可加工机器

核心代码:

if r<self.p1 or r>1-self.p2: for k in range(len(n_machine)):m=int(n_machine[k])-1index_select.append(m)t=n_time[k]a_global[0,m]+=t               #全局负荷计算a_part[0,m]+=t                 #局部负荷计算if r<self.p1:                       #全局选择select=a_global[:,index_select]idx_select=np.argmin(select[0])else:                               #局部选择select=a_part[:,index_select]idx_select=np.argmin(select[0])m_select=n_machine[idx_select]t_index=n_machine.index(m_select)machine[i].append(m_select)machine_time[i].append(n_time[t_index])
else:                               #否则随机挑选机器                                index=np.random.randint(0,len(n_time),1)machine[i].append(n_machine[index[0]])machine_time[i].append(n_time[index[0]])

遗传算法

遗传算法(Genetic Algorithm,GA)是由John Holland教授在19世纪70年代率先提出,它是模拟自然界“优胜劣汰”淘汰机制的一种智能优化算法。由于该算法的算法稳健性、求解问题的广泛性及坚实的生物基础,该算法法一提出就受到很多学者亲睐。40多年国内外学者的共同研究已经让该算法变得成熟,其应用也较广。

相较于其它算法来说,遗传算法已经是一种较为成熟的算法,其在是算法本身的理论研究,与其他算法、方法的融合以及应用都取得很多成果。遗传算法的求解思路是模拟染色体基因的交叉、重组和突变,设计相关操作算子对问题解进行迭代,在达到最大迭代次数或者满足收敛条件得到问题的解。基于物种遗传规律设计的操作算子,一般包括选择、交叉和变异等算子。

遗传算法的基本要素主要包括:特定问题的染色体编码方式(解的表达)、种群的初始化方法、解码方式、选择、交叉和变异操作。基本遗传算法的流程描述如下:

Stepl:确定染色体编码方式,初始化一定规模的种群;

Step2:特定的解码方法对染色体解码,计算各个染色体的适应度值;

Step3:在交叉概率下对种群的个体进行交叉操作;

Step4:在变异概率下种群的个体进行变异操作;

Step5:按照选择策略选择下一代种群;判断是否达到终止条件,如果满足,则输出优化结果,否则转至Step2

遗传算法设计

参考文献的工序编码的变异方法是找出邻域最优的个体,计算量是所选择基因个数的阶乘,比较复杂,选择两个点对换基因的方式进行变异,即逆转变异。

简单来说:每次迭代以上一次迭代得到种群为基础,工序编码和机器编码分别进行pox交叉和均匀交叉,然后进行逆转变异和选择最小加工机器的变异,第一次迭代以初始种群为基础。
算法步骤:

  • 步骤1:初始化多个工序,机器,加工时间编码,解码得到加工时间
  • 步骤2:交叉概率下工序编码进行pox交叉,机器编码进行均匀交叉
  • 步骤3:变异概率下工序编码进行逆转变异,机器编码进行挑选最小加工机器
  • 步骤4:判断是否达到最大迭代次数,是的话输出结果,否则锦标赛选择种群,转到步骤2

pox交叉
以mk01为例:初始工件编号为6,对应两个进行交叉的工序编码,0到6基因及其位置保持不变,每个编码6到9的基因位置按顺序填入另一个工序编码6到9的基因。

核心代码:

def job_cross(self,chrom_L1,chrom_L2):       #工序的pox交叉num=list(set(chrom_L1[0]))np.random.shuffle(num)index=np.random.randint(0,len(num),1)[0]jpb_set1=num[:index+1]                  #固定不变的工件jpb_set2=num[index+1:]                  #按顺序读取的工件C1,C2=np.zeros((1,chrom_L1.shape[1]))-1,np.zeros((1,chrom_L1.shape[1]))-1sig,svg=[],[]for i in range(chrom_L1.shape[1]):#固定位置的工序不变ii,iii=0,0for j in range(len(jpb_set1)):if(chrom_L1[0,i]==jpb_set1[j]):C1[0,i]=chrom_L1[0,i]else:ii+=1if(chrom_L2[0,i]==jpb_set1[j]):C2[0,i]=chrom_L2[0,i]else:iii+=1if(ii==len(jpb_set1)):sig.append(chrom_L1[0,i])if(iii==len(jpb_set1)):svg.append(chrom_L2[0,i])signal1,signal2=0,0             #为-1的地方按顺序添加工序编码for i in range(chrom_L1.shape[1]):if(C1[0,i]==-1):C1[0,i]=svg[signal1]signal1+=1if(C2[0,i]==-1):C2[0,i]=sig[signal2]signal2+=1return C1,C2

均匀交叉

均匀交叉算子的概念比较简单,简单说一下逻辑:假设两个解的工序编码的第一道工序分别选择了机器1和3,随机生成0,1两个数中的一个,如果随机数是1,交换两个解第一道工序的机器选择,否则保持原选择。

核心代码:

def ma_cross(self,m1,t1,m2,t2):  #机器均匀交叉MC1,MC2,TC1,TC2=[],[],[],[]for i in range(len(self.machines)):     MC1.append([]),MC2.append([]),TC1.append([]),TC2.append([]);for j in range(self.machines[i]):index=np.random.randint(0,2,1)[0]if(index==0):  #为0时继承继承父代的机器选择MC1[i].append(m1[i][j]),MC2[i].append(m2[i][j]),TC1[i].append(t1[i][j]),TC2[i].append(t2[i][j]);else:                #为1时另一个父代的加工机器选择MC2[i].append(m1[i][j]),MC1[i].append(m2[i][j]),TC2[i].append(t1[i][j]),TC1[i].append(t2[i][j]);return MC1,TC1,MC2,TC2

逆转变异

比较简单,交换两个位置的基因。代码:

def job_mul(self,job):location=random.sample(range(job.shape[1]),2)job[0,location[0]],job[0,location[1]]=job[0,location[1]],job[0,location[0]]return job

选择最小加工机器变异

首先挑选位置,然后对应位置的机器编码变为最小加工时间的机器,代码:

def ma_mul(self,machine,machine_time):for i in range(len(self.machines)):r=np.random.randint(0,self.machines[i],1)[0]   #挑选位置mul_idx=random.sample(range(self.machines[i]),r)for j in mul_idx:highs=self.tom[i][j]lows=self.tom[i][j]-self.tdx[i][j]         n_machine=self.Tmachine[i,lows:highs]      #取出加工机器n_time=self.Tmachinetime[i,lows:highs]      #取出加工时间machine_time[i][j]=min(n_time)              #挑选最小加工时间index=np.argwhere(n_time==machine_time[i][j])machine[i][j]=n_machine[index[0,0]]return machine,machine_time

锦标赛选择

对种群的个体进行放回抽样,每次随机抽取多个,选择最优的个体,代码:

for i in range(self.popsize):cab=random.sample(range(self.popsize*2),self.C_size)      #按照C_size生成一组不重复的索引用于锦标赛选择 index,time=[],[]for j in range(self.C_size):index.append(cab[j]),time.append(answer2[cab[j]]);  min_time=time.index(min(time))min_idx=index[min_time]work_job[i],work_M[i],work_T[i]=work_job2[min_idx],work_M2[min_idx],work_T2[min_idx] #选择出的个体,用于下次遗传answer[i]=answer2[min_idx]

具体的整个遗传算法代码细节在ga.py里。

结果

代码运行环境
windows系统,python3.6.0,第三方库及版本号如下:

numpy==1.18.5
matplotlib==3.2.1

第三方库需要在安装完python之后,额外安装,以前文章有讲述过安装第三方库的解决办法。

命令

oj=data_deal(10,6)               #工件数,机器数
Tmachine,Tmachinetime,tdx,work,tom,machines=oj.cacu()
parm_data=[Tmachine,Tmachinetime,tdx,work,tom,machines]
to=FJSP(10,6,0.3,0.4,parm_data)      #工件数,机器数,3种选择的概率和mk01的数据ho=GA(50,100,to,0.8,0.1,parm_data,4)     #4个数依次是迭代次数,种群规模,交叉概率,变异概率和锦标赛选择框的大小
job,machine,machine_time,result=ho.ga_total()
result=np.array(result).reshape(len(result),2)
plt.plot(result[:,0],result[:,1])                   #画完工时间随迭代次数的变化
font1={'weight':'bold','size':22}
plt.xlabel("迭代次数",font1)
plt.title("完工时间变化图",font1)
plt.ylabel("完工时间",font1)
plt.show()
to.draw(job,machine,machine_time)#画甘特图

运行结果

结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qNrjsD33-1646702502674)(https://gitee.com/XZDNF-1618/picture/raw/master/2022-2-8/1644293564216-11%20(1)].png)

帕累托解中完工时间迭代次数的变化图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Ofxdlu8-1646702502675)(https://gitee.com/XZDNF-1618/picture/raw/master/2022-2-8/1644293602867-11%20(2)].png)

解的甘特图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvvpovRd-1646702502675)(https://gitee.com/XZDNF-1618/picture/raw/master/2022-2-8/1644293602865-11%20(3)].png)

结论

完工时间大约能优化到42左右,可以调整参数,或者改进遗传算子。

甘特图有时会出现bug,和算法结果不一样,大多数时候是正确的,太过繁琐没有解决这个bug。
参考文献:柔性作业车间调度智能算法及其应用-高亮

车间调度问题完整代码,详见微信公众号:学长带你飞
扫描下方二维码,关注并回复关键词:车间调度,可得。

书本算法重现丨遗传算法:以算例MK01为例相关推荐

  1. 多目标柔性车间调度丨mogv算法:以算例MK01为例

    车间调度系列文章: 1.车间调度的编码.解码,调度方案可视化的探讨 2.多目标优化:浅谈pareto寻优和非支配排序遗传算法-NSGAII的非支配排序及拥挤度 3.柔性车间调度问题:以算例MK01初探 ...

  2. 车间调度丨粒子群算法初探:以算例MK01为例

    车间调度系列文章: 1.车间调度的编码.解码,调度方案可视化的探讨 2.多目标优化:浅谈pareto寻优和非支配排序遗传算法-NSGAII的非支配排序及拥挤度 3.柔性车间调度问题:以算例MK01初探 ...

  3. 车间调度-灰狼算法的应用:以算例MK01为例

    车间调度系列文章: 1.车间调度的编码.解码,调度方案可视化的探讨 2.多目标优化:浅谈pareto寻优和非支配排序遗传算法-NSGAII的非支配排序及拥挤度 3.柔性车间调度问题:以算例MK01初探 ...

  4. 多目标柔性车间调度丨NSGA-II:以算例MK01为例

    车间调度系列文章: 1.车间调度的编码.解码,调度方案可视化的探讨 2.多目标优化:浅谈pareto寻优和非支配排序遗传算法-NSGAII的非支配排序及拥挤度 3.柔性车间调度问题:以算例MK01初探 ...

  5. 【建模算法】基于遗传算法求解TSP问题(matlab求解)

    [建模算法]基于遗传算法求解TSP问题(matlab求解) TSP (traveling salesman problem,旅行商问题)是典型的NP完全问题,即其最坏情况下的时间复杂度随着问题规模的增 ...

  6. 06 聚类算法 - 代码案例二 - K-Means算法和Mini Batch K-Means算法比较

    03 聚类算法 - K-means聚类 04 聚类算法 - 代码案例一 - K-means聚类 05 聚类算法 - 二分K-Means.K-Means++.K-Means||.Canopy.Mini ...

  7. 算法的时间复杂度到底怎么算?

    算法的时间复杂度到底怎么算? 引言 假设计算机运行一行简单语句算作一次运算. def func1(num):print("Hello, World!\n") # 需要执行 1 次r ...

  8. 【老生谈算法】标准遗传算法的MATLAB实现源码——遗传算法

    标准遗传算法的MATLAB实现 1.原文下载: 本算法原文如下,有需要的朋友可以点击进行下载 序号 原文(点击下载) 本项目原文 [老生谈算法]标准遗传算法的MATLAB实现.doc 2.算法详解: ...

  9. 【优化算法】 简述遗传算法(GA)原理

    [优化算法]简述遗传算法(GA)原理 [优化算法]简述灰狼优化算法(GWO)原理 前言 遗传算法GA(Genetic algorithm)由美国密西根大学 J. Holland 教授于90年代提出来的 ...

最新文章

  1. elasticsearch7.x源码编译
  2. virtual box挂载 共享文件夹
  3. Java十大简单性能优化
  4. 小米10pro第二个摄像头下面_小米10至尊纪念版、小米10 Pro对比评测:至尊版“至尊”在哪里?...
  5. if嵌套while循环语句_Python学习笔记015--while循环嵌套
  6. 中国十大科技进展2项,世界十大科技进展6项生物相关;相比工程,生物与国际差距还是较大...
  7. 【力扣】NO.136.只出现一次的数字
  8. Redis-数据结构01-压缩列表(ziplist)
  9. iTOP4412 gdbserver安装
  10. poj3253Fence Repair
  11. 阿里矢量库的图标使用教程(在线,下载)
  12. linux服务器安装网卡驱动,Linux下如何安装网卡驱动
  13. HMC——Hamiltonian Monte Carlo笔记
  14. 安卓手机管理_安卓必备!!一个小工具干掉所有乱搞的APP,手机速度瞬间提升,管理后台应用...
  15. 浙大超厉害计算机硕士生导师
  16. 秃鹫入门4,GDB调试与OpenCV图像库
  17. java实现PC网站实现微信扫码登陆
  18. 新春特别策划:新春观影 与科幻电影难分舍的IT元素
  19. winpe镜像文件iso下载_教你如何使用iso文件安装系统_一键重装教程
  20. QQ书签的chrome扩展插件

热门文章

  1. 【论文阅读】LIO-SAM: Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping
  2. 微信小程序+uni-app知识点总结
  3. 哈啰出行 - 铸将:领导力培养
  4. 易语言和java接口_易语言写接口让其他调用 易语言api使用教程
  5. SpringBoot和SpringCloud配置
  6. 绿色全要素生产率,python,采用全局生产技术的弱可处置性非径向方向距离函数(NDDF),可调方向权重,DDF,DEA
  7. python分支判断语句_python 分支语句 等值判断 逻辑运算符
  8. 智能卡系统设计(一) 断电保护和数据备份
  9. TI AM335x 可编程实时模块(PRUSS)详解
  10. python3视频教程合集