【调度算法】开放车间调度问题遗传算法(failed)

省流:这是一个错误的代码备份,如果你需要可以直接运行的完整代码,请移步GitHub

本以为手搓了一个单机调度和并行机调度的遗传算法,就可以尝试写开放车间的遗传算法了,结果手搓了两天,开始作业时间和结束作业时间的计算还是没整明白。

后来参考了GitHub上一个作业车间调度问题的遗传算法代码,发现,哪有我这么写代码的,人家都是把各个对象和方法封装成一个一个的类,所谓的面向对象编程,我这写的是啥玩意。。。

所以决定这个算法就不纠缠了,因为继续按照我这样的逻辑写下去,基本写不通(我菜,你们要是能走通踢我),还不如重新捡起我面向对象的思想,从一开始就做好属性和功能的封装。

先把代码搁这备个份。

说明:除了cal_start_and_finish_time函数外,别的函数都是对的,改一下编码就可以直接用(不过这几个函数都挺简单的应该没人用得上),代码的编码方式我是参考的Genetic Algorithms for Open Shop Scheduling and Re-Scheduling这篇论文(其实这种编码方式我暂时看不出能有啥出类拔萃的效果,单纯因为它不是主流的编码方式,又比较好理解,所以做了一个尝试)。

GitHub上大佬写的作业车间传统遗传算法代码我给看明白了,争取尽量把开放车间的代码封装出来。

以上,又是觉得自己是个大菜逼的一天5555。

import random
import numpy as np
import matplotlib.pyplot as plt
import copy# TODO: 暂时看不懂这种有工序约束的多机调度问题怎么编码(这个是作业车间的,先看开放车间问题)
# # 机器约束矩阵(10个工件,5台机器)
# machine_constraint_matrix = [[2, 1, 4, 2, 1, 2, 4, 3, 4, 5],
#                              [1, 4, 5, 1, 4, 3, 5, 1, 2, 4],
#                              [5, 5, 2, 5, 3, 5, 2, 2, 5, 3],
#                              [4, 3, 3, 3, 2, 1, 3, 4, 1, 2],
#                              [3, 2, 1, 4, 5, 4, 1, 5, 3, 1]]
# # 加工时间矩阵
# pro_time_matrix = [[53, 21, 12, 55, 83, 92, 93, 60, 44, 96],
#                    [21, 71, 42, 77, 19, 54, 87, 41, 49, 75],
#                    [34, 26, 31, 66, 64, 43, 87, 38, 98, 43],
#                    [55, 52, 39, 77, 34, 62, 69, 24, 17, 79],
#                    [95, 16, 98, 79, 37, 79, 77, 83, 25, 77]]# m台相同的机器,n个工件,每个工件有1道工序,可任意选择1台机器进行加工# 定义遗传算法参数
POP_SIZE = 100  # 种群大小
MAX_GEN = 100  # 最大迭代次数
CROSSOVER_RATE = 0.7  # 交叉概率
MUTATION_RATE = 0.2  # 变异概率def sort_by_id(id, sequence):# 根据id对sequence进行排序new_sequence = sequence[:]for i in range(len(id)):sequence[i] = new_sequence[id[i]]# 随机生成初始种群,这里用一个元组表示工件和机器的分配关系,如元组(0,1)表示编号为1的工件在编号为0的机器上加工,工件和机器编码都是从0开始
def get_init_pop(pop_size):pop = []job = [(m, n) for m in range(machine_num) for n in range(len(job_id))]for _ in range(pop_size):random.shuffle(job)pop.append(job[:])return pop# TODO: 开始时间和结束时间计算有问题,这个函数废了
# 将输入的一维job进行二维转换,计算start_time和finish_time
def cal_start_and_finish_time(job):# 按照输入的工序进行排序sorted_job = sorted(job, key=lambda x: x[0])  # 按照设备排序sorted_pro_time = [pro_times[j[0]][j[1]] for j in sorted_job]  # 对应的加工时间# 转换成二维列表sorted_job = [sorted_job[i:i + len(job_id)] for i in range(0, len(sorted_job), len(job_id))]sorted_pro_time = [sorted_pro_time[i:i + len(job_id)] for i in range(0, len(sorted_pro_time), len(job_id))]# 对每台机器的总加工时间进行加和,用于排序# 这里直接规定当各机器无法同时开工时,选择总加工时间最长的机器最先开工start_seq = [i[0] for i in sorted(enumerate(pro_times), key=lambda x: sum(x[1]), reverse=True)]  # 机器开始加工的顺序start_time = [[] for _ in range(len(sorted_job))]finish_time = [[] for _ in range(len(sorted_job))]# 第一台开工的机器的第一个工件的start_time和finish_timestart_time[start_seq[0]].append(arr_times[sorted_job[start_seq[0]][0][1]])finish_time[start_seq[0]].append(start_time[start_seq[0]][0] + sorted_pro_time[start_seq[0]][0])# 单独先把第一个开工的机器的start_time和finish_time计算出来for j in range(1, len(pro_times[0])):start_time[start_seq[0]].append(max(finish_time[start_seq[0]][-1], arr_times[sorted_job[start_seq[0]][j][1]]))finish_time[start_seq[0]].append(start_time[start_seq[0]][j] + sorted_pro_time[start_seq[0]][j])# 计算每台机器的第一个工件的开始加工时间for i in range(1, len(start_seq)):# 一个工件不能同时在两台机器加工start_time[start_seq[i]].append(-1)for k in range(i):if sorted_job[start_seq[i]][0][1] == sorted_job[start_seq[k]][0][1]:start_time[start_seq[i]][-1] = finish_time[start_seq[k]][0]elif k == i - 1 and start_time[start_seq[i]][-1] == -1:start_time[start_seq[i]][-1] = arr_times[sorted_job[start_seq[i]][0][1]]finish_time[start_seq[i]].append(start_time[start_seq[i]][0] + sorted_pro_time[start_seq[i]][0])# 计算其他行列for i in range(1, len(start_seq)):for j in range(1, len(pro_times[0])):start_time[start_seq[i]].append(-1)for k in range(i):# 写着写着突然发现不对,还是需要判断前边两台机器上正在加工的工件是不是当前机器即将要加工的工件# 感觉这里把自己绕进去了,实际上,当某个工件在当前机器上的加工时间特别大,可能是其在别的机器上加工时间的几倍或者是别的工件加工时间之和的时候,这个if判断还要向前或者向后搜索很多轮# 但是如果真有这样一道工序存在,应该不需要什么算法直接可以看出结果,所以这里只搜索相邻的两轮# TODO: but,逻辑还是欠严谨,这是一段失败的代码,或许证明这思路就不行?先到这里吧,麻了if finish_time[start_seq[i]][j - 1] <= finish_time[start_seq[k]][j - 1]:if sorted_job[start_seq[i]][j][1] == sorted_job[start_seq[k]][j - 1][1]:start_time[start_seq[i]][-1] = max(finish_time[start_seq[i]][-1],finish_time[start_seq[k]][j - 1])elif k == i - 1 and start_time[start_seq[i]][-1] == -1:start_time[start_seq[i]][-1] = max(finish_time[start_seq[i]][-1],arr_times[sorted_job[start_seq[i]][j][1]])elif finish_time[start_seq[k]][j - 1] < finish_time[start_seq[i]][j - 1] <= finish_time[start_seq[k]][j]:if sorted_job[start_seq[i]][j][1] == sorted_job[start_seq[k]][j][1]:start_time[start_seq[i]][-1] = max(finish_time[start_seq[i]][-1], finish_time[start_seq[k]][j])elif k == i - 1 and start_time[start_seq[i]][-1] == -1:start_time[start_seq[i]][-1] = max(finish_time[start_seq[i]][-1],arr_times[sorted_job[start_seq[i]][j][1]])else:start_time[start_seq[i]][-1] = max(finish_time[start_seq[i]][-1],arr_times[sorted_job[start_seq[i]][j][1]])finish_time[start_seq[i]].append(start_time[start_seq[i]][j] + sorted_pro_time[start_seq[i]][j])return sorted_job, sorted_pro_time, start_time, finish_time# 计算染色体的适应度(makespan) 以最小化交货期延时为目标函数,这里计算的是交货期总延时时间
def fitness(job):sorted_job, sorted_pro_time, start_time, finish_time = cal_start_and_finish_time(job)# 计算适应度,目标函数是最小化总延货期max_finish_time = []  # 记录每个工件在各机器上的最后的完工时间for k in range(len(job_id)):# 定位,定位到sorted_job中所有元组的第二个元素为i的索引indices = [(i, j) for i, row in enumerate(sorted_job) for j, (x, y) in enumerate(row) if y == k]max_ft = 0for id in indices:max_ft = finish_time[id[0]][id[1]] if finish_time[id[0]][id[1]] > max_ft else max_ftmax_finish_time.append(max_ft)delay_time = [max(mf - d, 0) for mf, d in zip(max_finish_time, deadlines)]  # 总延货期# print("sorted_job=",sorted_job)# print("sorted_pro_time=",sorted_pro_time)# print("start_time=",start_time)# print("finish_time=",finish_time)# print("delay_time=",delay_time)# print("sum(delay_time)=",sum(delay_time))return sum(delay_time)# 选择父代,这里选择POP_SIZE/2个作为父代
def selection(pop):fitness_values = [1 / fitness(job) for job in pop]  # 以最小化交货期总延时为目标函数,这里把最小化问题转变为最大化问题total_fitness = sum(fitness_values)prob = [fitness_value / total_fitness for fitness_value in fitness_values]  # 轮盘赌,这里是每个适应度值被选中的概率# 按概率分布prob从区间[0,len(pop))中随机抽取size个元素,不允许重复抽取,即轮盘赌选择selected_indices = np.random.choice(len(pop), size=POP_SIZE // 2, p=prob, replace=False)return [pop[i] for i in selected_indices]# 交叉操作 这里是单点交叉
def crossover(job_p1, job_p2):cross_point = random.randint(1, len(job_p1) - 1)job_c1 = job_p1[:cross_point] + [gene for gene in job_p2 if gene not in job_p1[:cross_point]]job_c2 = job_p2[:cross_point] + [gene for gene in job_p1 if gene not in job_p2[:cross_point]]return job_c1, job_c2# 变异操作,因为元组是不可变类型,这里采取的变异方式是随机交换两个点
def mutation(job):while True:index1 = random.randint(0, len(job) - 1)index2 = random.randint(0, len(job) - 1)if index1 != index2:breaktemp = job[index1]job[index1] = job[index2]job[index2] = tempreturn job# 主遗传算法循环
# 以最小化延迟交货时间为目标函数
def GA():  # 工件加工顺序是否为无序best_job = [(m, n) for m in range(machine_num) for n in range(len(job_id))]  # 初始化最佳个体best_makespan = fitness(best_job)  # 获得最佳个体的适应度值# 创建一个空列表来存储每代的适应度值fitness_history = [best_makespan]pop = get_init_pop(POP_SIZE)for _ in range(1, MAX_GEN + 1):pop = selection(pop)  # 选择new_population = []while len(new_population) < POP_SIZE:parent1, parent2 = random.sample(pop, 2)  # 不重复抽样2个if random.random() < CROSSOVER_RATE:child1, child2 = crossover(parent1, parent2)  # 交叉new_population.extend([child1, child2])else:new_population.extend([parent1, parent2])pop = [mutation(job) if random.random() < MUTATION_RATE else job for job in new_population]  # 变异best_gen_job = min(pop, key=lambda x: fitness(x))best_gen_makespan = fitness(best_gen_job)  # 每一次迭代获得最佳个体的适应度值# print(job_id)# print(best_gen_job)# print(best_gen_makespan,best_makespan,best_gen_makespan < best_makespan)if best_gen_makespan < best_makespan:  # 更新最小fitness值best_makespan = best_gen_makespanbest_job = copy.deepcopy(best_gen_job)fitness_history.append(best_makespan)  # 把本次迭代结果保存到fitness_history中(用于绘迭代曲线)# print(best_job)# print(best_makespan)# print('==========================')# 绘制迭代曲线图plt.plot(range(MAX_GEN + 1), fitness_history)plt.xlabel('Generation')plt.ylabel('Fitness Value')plt.title('Genetic Algorithm Convergence')plt.show()return best_job, best_makespandef plot_gantt(job):# 准备一系列颜色colors = ['blue', 'yellow', 'orange', 'green', 'palegoldenrod', 'purple', 'pink', 'Thistle', 'Magenta', 'SlateBlue','RoyalBlue', 'Cyan', 'Aqua', 'floralwhite', 'ghostwhite', 'goldenrod', 'mediumslateblue', 'navajowhite','moccasin', 'white', 'navy', 'sandybrown', 'moccasin']job_colors = random.sample(colors, len(job) // machine_num)# 计算每个工件的开始时间和结束时间sorted_job, sorted_pro_time, start_time, finish_time = cal_start_and_finish_time(job)id = [[0] * len(sorted_job[0]) for _ in range(machine_num)]job_color = [[0] * len(sorted_job[0]) for _ in range(machine_num)]for i in range(machine_num):for j in range(len(id[0])):id[i][j] = sorted_job[i][j][1]job_color[i][j] = job_colors[id[i][j]]print("sorted_job=", sorted_job)print("sorted_pro_time=", sorted_pro_time)print("start_time:", start_time)print("finish_time:", finish_time)# 创建图表和子图plt.figure(figsize=(12, 6))# 绘制工序的甘特图for i in range(len(start_time)):for j in range(len(start_time[i])):plt.barh(i, finish_time[i][j] - start_time[i][j], height=0.5, left=start_time[i][j], color=job_color[i][j],edgecolor='black')plt.text(x=(start_time[i][j] + finish_time[i][j]) / 2, y=i, s=id[i][j], fontsize=14)# 设置纵坐标轴刻度为机器编号machines = [f'Machine {i}' for i in range(len(start_time))]plt.yticks(range(len(machines)), machines)# 设置横坐标轴刻度为时间# start = min([min(row) for row in start_time])start = 0end = max([max(row) for row in finish_time])plt.xticks(range(start, end + 1))plt.xlabel('Time')# 图表样式设置plt.ylabel('Machines')plt.title('Gantt Chart')# plt.grid(axis='x')# 自动调整图表布局plt.tight_layout()# 显示图表plt.show()if __name__ == '__main__':# n个工件,每个工件都需要到m台不同机器上各加工一次,加工顺序任意,每台机器上的加工时间已知job_id = [0, 1, 2, 3, 4, 5, 6, 7, 8]  # 工件编号pro_times = [[4, 7, 6, 5, 8, 3, 5, 5, 10],[7, 10, 1, 5, 7, 5, 8, 7, 3],[7, 1, 8, 9, 3, 7, 8, 6, 1]]  # 加工时间arr_times = [3, 2, 4, 5, 3, 2, 1, 8, 6]  # 到达时间deadlines = [46, 35, 49, 41, 40, 48, 49, 37, 36]  # 交货期machine_num = 3  # 3台完全相同的并行机,编号为0,1,2best_job, best_makespan = GA()print("最佳调度顺序和分配:", best_job)print("最小交货期延时时间:", best_makespan)plot_gantt(best_job)# job_id = [0, 1, 2, 3]  # 工件编号# pro_times = [[4, 7, 6, 5],#              [7, 10, 1, 5],#              [7, 1, 8, 9]]  # 加工时间# arr_times = [3, 2, 4, 5]  # 到达时间# deadlines = [6, 5, 9, 11]  # 交货期# machine_num = 3  # 3台完全相同的并行机,编号为0,1,2# # best_job, best_makespan = GA()# # print("最佳调度顺序和分配:", best_job)# print("最小交货期延时时间:", best_makespan)# # plot_gantt(best_job)# job = [(1, 2), (0, 2), (1, 1), (2, 2), (2, 0), (0, 0), (0, 1), (0, 3), (1, 0), (2, 1), (2, 3), (1, 3)]# cal_start_and_finish_time(job)# plot_gantt(job)

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

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

相关文章

1、Mysql架构与历史

Mysql逻辑架构 最上层是服务并不是Mysql所独有的&#xff0c;大多数基于网络的客户端/服务器的工具或者服务都有类似的架构&#xff0c;比如连接处理&#xff0c;授权认证&#xff0c;安全等。 第二层是Mysql比较有意思的部分。大多数Mysql的核心服务都在这一层&#xff0c;…

torch.view()和.reshape()

view只能作用在连续的张量上&#xff08;张量中元素的内存地址是连续的&#xff09;。而reshape连续or非连续都可以。 调用x.reshape的时候&#xff0c;如果x在内存中是连续的&#xff0c;那么x.reshape会返回一个view&#xff08;原地修改&#xff0c;此时内存地址不变…

用户与组管理:如何在服务器系统中管理用户和权限

你是否想过&#xff0c;当你登录到一个服务器系统时&#xff0c;你是如何被识别和授权的&#xff1f;你是否知道&#xff0c;你可以通过创建和管理用户和组来简化和优化你的系统管理工作&#xff1f;你是否想了解一些常用的用户和组管理命令和技巧&#xff1f;如果你的答案是肯…

c语言实现简单的string

文章目录 前言一、注意事项二、代码valgrind扫描总结 前言 在c语言中利用面向对象的编程方式&#xff0c;实现类似c中的string类。 一、注意事项 所有与string结构体相关的函数全都没有返回值。 在c中&#xff0c;当产生临时对象时编译器会自动的加入析构函数&#xff0c;销毁…

Walrus 入门教程:如何创建模板以沉淀可复用的团队最佳实践

模板是 Walrus 的核心功能之一&#xff0c;模板创建完成后用户可以重复使用&#xff0c;并在使用过程中逐渐沉淀研发和运维团队的最佳实践&#xff0c;进一步简化服务及资源的部署。用户可以使用 HCL 语言自定义创建模板&#xff0c;也可以一键复用 Terraform 社区中上万个成熟…

云原生安全工具汇总(docker、k8s、Kubernetes、Git仓库)

目录 Metarget:云原生靶机环境 CDK:容器环境定制的渗透测试工具 container-escape-check:容器逃逸检测

synchronized在代码中的用法

synchronized可以对两种对象加锁&#xff1a;实例对象和类对象。下边先说对类对象加锁的代码&#xff1a; 第1是修饰static方法&#xff0c;第2种是直接锁类的class对象&#xff1b; /*** title: SynchronizedStaticDemo1* description: synchronized 对类加锁1* author: * d…

【Python百宝箱】Python数据探险:Excel与数据科学的完美结合

前言 在当今信息爆炸的时代&#xff0c;数据处理和分析已经成为各行各业不可或缺的一部分。在众多数据处理工具中&#xff0c;Python以其简洁而强大的语法成为数据科学家和分析师的首选之一。本文将深入探讨与电子表格处理相关的Python库&#xff0c;介绍它们的功能、应用场景…

批量按顺序1、2、3...重命名所有文件夹里的文件

最新&#xff1a; 最快方法&#xff1a;先用这个教程http://文件重命名1,2......nhttps://jingyan.baidu.com/article/495ba841281b7079b20ede2c.html再用这个教程去空格&#xff1a;利用批处理去掉文件名中的空格-百度经验 (baidu.com) 以下为原回答 注意文件名有空格会失败…

LeetCode Hot100 105.从前序与中序遍历序列构造二叉树

题目&#xff1a;给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 代码&#xff1a; class Solution {private Map<Integer, Integer> indexM…

ESP32网络开发实例-远程Web串口监视器

远程Web串口监视器 文章目录 远程Web串口监视器1、应用介绍2、软件准备3、硬件准备4、代码实现在本文中,我们将构建一个 ESP32 网络服务器,用作远程串行监视器。 基于 Web 的串行监视器的工作方式与通常用于调试目的的 Arduino IDE 串行监视器的工作方式相同。 1、应用介绍 …

数字逻辑电路基础-时序逻辑电路之移位寄存器

文章目录 一、移位寄存器定义二、verilog源码三、仿真结果一、移位寄存器定义 移位寄存器定义 A shift register is a type of digital circuit using a cascade of flip flops where the output of one flip-flop is connected to the input of the next. 移位寄存器是一种将…

docker部署MySQL5.7设置密码和远程访问的方法

运行MySQL docker run -p 3306:3306 --name mysql57 -v /root/mysql/log:/var/log/mysql -v /root/mysql/data:/var/lib/mysql -v /root/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORDD7txumqc2b! -d mysql:5.7 --character-set-serverutf8mb4 --collation-serverutf8…

c++八股文记录

八股文 1.类和结构体的区别 在 C 中&#xff0c;类&#xff08;class&#xff09;和结构体&#xff08;struct&#xff09;在语法上几乎是相同的&#xff0c;唯一的区别是默认的访问权限。在结构体中&#xff0c;默认的访问权限是公有的&#xff08;public&#xff09;&#x…

基于51单片机超市快递寄存自动柜设计源程序

一、系统方案 1、本设计采用这51单片机作为主控器。 2、存包&#xff0c;GSM短信取件码。 3、液晶1620显示。 4、矩阵键盘输入取件码&#xff0c;完成取包。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 /******************************…

python基于flask_sockets实现WebSocket

WebSocket是啥&#xff1f; WebSocket是HTML5引入的新的通信协议&#xff0c;主要由Web客户端和服务器实现&#xff0c;当然它也可以在Web之外实现。 与HTTP连接不同&#xff0c;WebSocket连接是客户端和服务器之间永久的双向通信通道&#xff0c;其中任何一个都可以启动交换。…

量子计算的发展

目录 一、量子力学的发展历程二、量子计算的发展历程三、量子计算机的发展历程四、量子信息科学的发展 一、量子力学的发展历程 量子力学是现代物理学的一个基本分支&#xff0c;它的发展始于20世纪初。以下是量子力学发展的几个重要阶段&#xff1a; 普朗克&#xff08;1900&…

steam搬砖还能做吗?CSGO饰品未来走势如何?

steam/csgo搬砖项目真能月入过万吗&#xff1f;到底真的假的&#xff1f; 如何看待CSGO饰品市场的整体走向&#xff1f; 从整体来说&#xff0c;CSGO的饰品市场与规模肯定会持续不断的上升&#xff0c;大盘不会发生特别大的波动&#xff0c;目前处于稳定期&#xff01;&#x…

WGCLOUD 中文繁体版本 下载

wgcloud 繁体版下载 下載繁體版安裝包 - WGCLOUD

Compose入门

​ 本篇文章主要是为了对Compose有一个初步了解。知道Compose是做什么的&#xff0c;用Compose能干什么&#xff0c;在目前的各种UI框架下面有些优势&#xff0c;参考Google官网的解释加上一些自己的理解生成的一篇文章。本人也是Compose初学者&#xff0c;通过每一步学习遇到哪…