【调度算法】并行机调度问题遗传算法

news2024/11/27 8:42:34

问题描述

m台相同的机器,n个工件,每个工件有1道工序,可按照任意的工序为每个工件分配一台机器进行加工

工件ABCDEFGHI
工件编号012345678
加工时间4765835510
到达时间324532186
交货期101530241413201810

设备数目:3

目标函数

最小化交货期总延时时间

编码说明

记机器数为m,从0开始编号为0,1,...,m-1,记工件数为n,同样从0开始编号。

定义两个变量job_idjob,前者表示工件的加工顺序(不是严格意义上的先加工A再加工B这种顺序,这里的每个工件都是独立的,整一个id只是为了再分配完机器之后自然就能选出一种加工顺序),后者表示每个工件用哪台机器加工。

例如,job_id=[4, 0, 5, 8, 1, 6, 2, 7, 3]job=[0, 1, 2, 2, 1, 0, 2, 1, 0]表示“编号为4的工件被分配给了编号为0的机器”,“编号为0的工件被分配给了编号为1的机器”,编号为0的机器上工件加工的先后顺序为4,6,3,其余类推。

注意,并行机调度问题里边对于染色体的编码一般分为机器选择部分工件排序部分,机器选择部分,就是正常这里应该是先给工件分配机器,再对每台工件上分配的机器进行排序,但是我这个代码里就是先直接对工件进行乱序然后再选择机器,乍一听好像最后的效果差不多,但是看代码就会知道,我代码里是对job_id进行乱序之后,直接就一种群为单位进行选择交叉变异了。即,一个job_id值对应一个种群(而非一个个体,但是理论上应该是每个个体对对饮过一个不同的顺序),就可能会导致处理大规模问题的时候时间复杂度太高(这里确实是偷懒了但是我这两天看代码真的看麻了5555,菜是原罪),有能力的好兄弟改好了可以踢我一下。

具体思路可以看这篇:https://blog.csdn.net/qq_38361726/article/details/120669250

运算结果

最佳加工顺序: [4, 0, 5, 8, 1, 6, 2, 7, 3]
最佳调度分配: [0, 1, 2, 2, 1, 0, 2, 1, 0]
最小交货期延时时间: 7

在这里插入图片描述

在这里插入图片描述

python代码

import random
import numpy as np
import matplotlib.pyplot as plt
import copy


# 定义遗传算法参数
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]]


# 随机生成初始种群,这里的每个个体表示第i个工件选择在第choose[i]台机器进行加工,工件和机器编码都是从0开始
def get_init_pop(pop_size):
    pop = []
    for _ in range(pop_size):
        choose = []
        for _ in range(len(job_id)):
            choose.append(random.randint(0, machine_num - 1))
        pop.append(list(choose))
    return pop


# 计算染色体的适应度(makespan) 以最小化交货期延时为目标函数,这里计算的是交货期总延时时间
def fitness(job):
    delay_times = [[] for _ in range(machine_num)]  # 每个工件超过交货期的延时时间
    finish_times = [[] for _ in range(machine_num)]  # 每个工件完成加工的时间点
    for i in range(len(job)):
        if finish_times[job[i]]:
            finish_times[job[i]].append(
                pro_times[job_id[i]] + max(finish_times[job[i]][-1], arr_times[job_id[i]]))
        else:
            finish_times[job[i]].append(pro_times[job_id[i]] + arr_times[job_id[i]])
        delay_times[job[i]].append(max(finish_times[job[i]][-1] - deadlines[job_id[i]], 0))

    return sum(element for sublist in delay_times for element in sublist)


# 选择父代,这里选择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] + job_p2[cross_point:]
    job_c2 = job_p2[:cross_point] + job_p1[cross_point:]
    return job_c1, job_c2


# 变异操作
def mutation(job):
    index = random.randint(0, len(job) - 1)
    job[index] = random.randint(0, machine_num - 1)  # 这样的话变异概率可以设置得大一点,因为实际的变异概率是MUTATION_RATE*(machine_num-1)/machine_num
    return job


# 主遗传算法循环
# 以最小化延迟交货时间为目标函数
# TODO: 没有考虑各机器的负载均衡
def GA(is_shuffle):  # 工件加工顺序是否为无序
    best_id = job_id  # 初始化job_id
    best_job = [0, 0, 0, 0, 0, 0, 0, 0, 0]  # 获得最佳个体
    # "makespan" 是指完成整个生产作业或生产订单所需的总时间,通常以单位时间(例如小时或分钟)来衡量。
    best_makespan = fitness(best_job)  # 获得最佳个体的适应度值
    # 创建一个空列表来存储每代的适应度值
    fitness_history = [best_makespan]

    pop = get_init_pop(POP_SIZE)
    for _ in range(1, MAX_GEN + 1):
        if is_shuffle:
            random.shuffle(job_id)
        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)  # 每一次迭代获得最佳个体的适应度值

        if best_gen_makespan < best_makespan:  # 更新最小fitness值
            best_makespan = best_gen_makespan
            best_job = copy.deepcopy(best_gen_job)  # TODO: 不用deepcopy的话不会迭代,但是这里应该有更好的方法
            best_id = copy.deepcopy(job_id)
        fitness_history.append(best_makespan)  # 把本次迭代结果保存到fitness_history中(用于绘迭代曲线)

    # 绘制迭代曲线图
    plt.plot(range(MAX_GEN + 1), fitness_history)
    plt.xlabel('Generation')
    plt.ylabel('Fitness Value')
    plt.title('Genetic Algorithm Convergence')
    plt.show()

    return best_id, best_job, best_makespan


def plot_gantt(job_id, 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))
    # 计算每个工件的开始时间和结束时间
    start_time = [[] for _ in range(machine_num)]
    end_time = [[] for _ in range(machine_num)]
    id = [[] for _ in range(machine_num)]
    job_color = [[] for _ in range(machine_num)]

    for i in range(len(job)):
        if start_time[job[i]]:
            start_time[job[i]].append(max(end_time[job[i]][-1], arr_times[job_id[i]]))
            end_time[job[i]].append(start_time[job[i]][-1] + pro_times[job_id[i]])
        else:
            start_time[job[i]].append(arr_times[job_id[i]])
            end_time[job[i]].append(start_time[job[i]][-1] + pro_times[job_id[i]])
        id[job[i]].append(job_id[i])
        job_color[job[i]].append(job_colors[job_id[i]])

    # 创建图表和子图
    plt.figure(figsize=(12, 6))

    # 绘制工序的甘特图
    for i in range(len(start_time)):
        for j in range(len(start_time[i])):
            plt.barh(i, end_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] + end_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 = 0
    end = max([max(row) for row in end_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__':
    # 定义多机调度问题的工件和加工时间
    job_id =    [0, 1, 2, 3, 4, 5, 6, 7, 8]  # 工件编号
    pro_times = [4, 7, 6, 5, 8, 3, 5, 5, 10]  # 加工时间
    arr_times = [3, 2, 4, 5, 3, 2, 1, 8, 6]  # 到达时间
    deadlines = [10, 15, 30, 24, 14, 13, 20, 18, 10]  # 交货期
    machine_num = 3  # 3台完全相同的并行机,编号为0,1,2

    job_id, best_job, best_makespan = GA(True)

    print("最佳加工顺序:", job_id)
    print("最佳调度分配:", best_job)
    print("最小交货期延时时间:", best_makespan)
    plot_gantt(job_id, best_job)

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

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

相关文章

基于java+springboot+vue的幼儿园信息网站

项目介绍 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于幼儿园管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了幼儿园管理系统&#xff0c;它彻底改变了过…

基于卷积优化算法的无人机航迹规划-附代码

基于卷积优化算法的无人机航迹规划 文章目录 基于卷积优化算法的无人机航迹规划1.卷积优化搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用卷积优化算法来优化无人机航迹规划。 …

EOCR-3BZ2/FBZ2的三种接点输出方式

施耐德EOCR-3BZ2/FBZ2电动机保护器具有体积小、精度高、抗干扰能力强、内置零序互感器等特点&#xff0c;同时具有低频运行和温、湿度检测功能。为适应不同的控制要求&#xff0c;EOCR-3BZ2/FBZ2电动机保护器具有2种输出方式&#xff0c;具体如下 输出接点&#xff1a; 接线图…

MicroPython ESP32 RTC功能使用介绍

MicroPython ESP32 RTC功能使用介绍 &#x1f4cc;Micropython esp32官方文档介绍&#xff1a;https://docs.micropython.org/en/latest/esp32/quickref.html#real-time-clock-rtc&#x1f516;本示例基于Thonny平台开发。&#x1f33f;使用ESP32S3开发板测试。✨所使用的固件版…

软件测试入门之接口测试

首先&#xff0c;什么是接口呢&#xff1f; 接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口&#xff1a;比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你…

Google Chrome 浏览器 119.0.6045.106 版本提示 STATUS_INVALID_IMAGE_HASH 崩溃

问题 今天更新 Google Chrome 浏览器到 119.0.6045.106 版本&#xff0c;然后访问页面不是空白&#xff0c;就是页面崩溃了 解决方案 我在网上找了几种&#xff0c;下面这个方式符合&#xff0c;能解决我的问题&#xff0c;就是在快捷方式的属性那里&#xff0c;找到目标给它…

AndroidStudio 运行报错:Invalid keystore format

AndroidStudio 运行报错&#xff1a;Invalid keystore format 把这玩意儿删了重新打开Android Studio运行一下就好了&#xff01;&#xff01;&#xff01;

OJ中常用平衡树,Treap树堆详解

文章目录 Treap定义Treap的可行性Treap的构建节点定义旋转左单旋右单旋旋转的代码实现 插入插入的代码实现 删除遍历查找Treap对权值的扩展Treap对size的扩展扩展size域后的节点定义和旋转&#xff0c;插入&#xff0c;删除操作查询第k小的元素求元素的排名 查询后继、前驱Trea…

vs code 和 hbuilder 历史记录查询

一.Hbuilder 找到需要的文件右键 二. vs code

基于人工兔算法的无人机航迹规划-附代码

基于人工兔算法的无人机航迹规划 文章目录 基于人工兔算法的无人机航迹规划1.人工兔搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用人工兔算法来优化无人机航迹规划。 1.人工兔…

最长非递减子序列,Python实现

from time import time from bisect import bisect from random import choices, seed from itertools import combinationsdef func1(seq):# 暴力穷举&#xff0c;从最长的子序列开始查找&#xff0c;大约耗时5小时for n in range(len(seq)-1, 0, -1): # 依次查找长度为len(se…

php实现钉钉机器人推送消息和图片内容(完整版)

先来看下实现效果: 代码如下: function send_dingtalk_markdown($webhook , $title , $message "", $atMobiles [], $atUserIds []) {$data ["msgtype" > "markdown","markdown" > ["title" > $title,&quo…

操作系统引论(二)

操作系统发展动力及技术基础 推动操作系统的发展和资源利用率的提高是相关联的。 让输入输出相对独立&#xff0c;通道技术&#xff0c;通道相当于简单的处理器&#xff0c;通过输入输出指令&#xff0c;控制外设完成输入输出。 输入和输出过程不是由主机控制的&#xff0c;是…

12 克莱姆法则的几何解释

克莱姆法则的几何解释 线性方程组求解正交变换克莱姆法则 这是关于3Blue1Brown "线性代数的本质"的学习笔记。 线性方程组求解 克莱姆法则并非解线性方程组的最好方法&#xff08;高斯消元法更好&#xff09;&#xff0c;了解它是为了加深对线性方程组的理解。 图…

华为李鹏:到 2025 年智能算力需求将达到目前水平的 100 倍

在第十四届全球移动宽带论坛上&#xff0c;华为高级副总裁、运营商 BG 总裁李鹏表示&#xff0c;大模型为代表的 AI 应用发展带来对智能算力的爆发式需求。 李鹏在题为《加速 5G 商业正循环&#xff0c;拥抱更繁荣的 5.5G》的讲话中表示&#xff0c;「5G 已经走在商业成功的正确…

Linux系统下数据同步服务RSYNC

一、RSYNC概述 1、什么是rsync rsync的好姐妹 sync 同步&#xff1a;刷新文件系统缓存&#xff0c;强制将修改过的数据块写入磁盘&#xff0c;并且更新超级块。 async 异步&#xff1a;将数据先放到缓冲区&#xff0c;再周期性&#xff08;一般是30s&#xff09;的去同步到磁…

初入网络安全人员必考的几本证书

目录 1. CISSP 2. CISP(注册信息安全人员&#xff09; 3. NISP&#xff08;“校园版的CISP”&#xff09; 4. CISP-PTE&#xff08;注册渗透测试工程师&#xff09; 5. CISP-IRE&#xff08;注册信息安全专业人员-应急响应工程师&#xff09; 6. CISP-A&#xff08;注册信…

MES系统防呆措施之具体场景学习

在工业设计上&#xff0c;为了避免使用者的操作失误造成机器或人身伤害&#xff08;包括无意识的动作或下意识的误动作或不小心的肢体动作&#xff09;&#xff0c;会针对这些可能发生的情况来做预防措施&#xff0c;称为防呆。对于注塑生产企业来讲&#xff0c;模具亦是企业的…

java web技术总结

HTML 非表单标签 1、b 粗体 u 下划线  i 斜体  del 删除效果 2、a 超链接 href target-blank 3、img 图片   4、frameset(frame) 框架集 5、table 表格 tb tr td (table data cell) colspan rowspan 6、ul li or 列表标签 7、embed 用来播放MP3、视频等等。 8、div 虚拟矩…

当今到底是哪个编程语言更吃香?

当今到底是哪个编程语言更吃香&#xff1f; 要我说&#xff0c;什么 Java、Python、Rust、JavaScript啥的&#xff0c;都不行。最吃香的当然是编程界最流行的E语言和M语言。 最近很多小伙伴找我&#xff0c;说想要一些 c语言的资料&#xff0c;然后我根据自己从业十年经验&am…