基于GA的FJSP柔性作业车间调度问题python实现(留言可获得完整代码)

附带详细的理论+代码详解视频,见某站lvqaq的数学建模

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


def GS(n, J, P):
    """
    n:机器数
    J:机器矩阵
    P:加工时间矩阵
    """
    MS = []
    time_list = np.zeros(n)
    job_num = len(J)        # 工件数量
    for i in range(job_num):    # i为工件编号
        job_list = J[i]              # job为该工件的工序列表
        for j in range(len(job_list)):       # j为工序编号
            min_time = 99999            # 最小时间初始化
            min_time_index = 0          # 最小位置初始化
            min_time_machine = 0
            machine_list = job_list[j]      # i工件的第j个工序的可选加工机器列表
            process_list = P[i][j]          # i工件的第j个工序的可选加工机器的加工时间列表
            if len(machine_list) == 1:
                MS.append(min_time_index)
                min_time_machine = machine_list[0]
                time_list[min_time_machine] += process_list[min_time_index]
            else:
                for m in range(len(machine_list)):  # m为该工序的可选加工机器列表的第m个机器,机器编号为machine_list[m]
                    temp_time = time_list[machine_list[m]] + process_list[m]
                    if temp_time < min_time:
                        min_time_machine = machine_list[m]
                        min_time = temp_time
                        min_time_index = m
                MS.append(min_time_index)
                time_list[min_time_machine] += process_list[min_time_index]
    return MS


def LS(n, J, P):
    """
    n:机器数
    J:机器矩阵
    P:加工时间矩阵
    """
    MS = []
    job_num = len(J)        # 工件数量
    for i in range(job_num):    # i为工件编号
        time_list = np.zeros(n)
        job_list = J[i]              # job为该工件的工序列表
        for j in range(len(job_list)):       # j为工序编号
            min_time = 99999            # 最小时间初始化
            min_time_index = 0          # 最小位置初始化
            min_time_machine = 0
            machine_list = job_list[j]      # i工件的第j个工序的可选加工机器列表
            process_list = P[i][j]          # i工件的第j个工序的可选加工机器的加工时间列表
            if len(machine_list) == 1:
                MS.append(min_time_index)
                min_time_machine = machine_list[0]
                time_list[min_time_machine] += process_list[min_time_index]
            else:
                for m in range(len(machine_list)):      # m为该工序的可选加工机器列表的第m个机器,机器编号为machine_list[m]
                    temp_time = time_list[machine_list[m]] + process_list[m]
                    if temp_time < min_time:
                        min_time_machine = machine_list[m]
                        min_time = temp_time
                        min_time_index = m
                MS.append(min_time_index)
                time_list[min_time_machine] += process_list[min_time_index]
    return MS


def RS(n, J, P):
    """
    n:机器数
    J:机器矩阵
    P:加工时间矩阵
    """
    MS = []
    job_num = len(J)        # 工件数量
    for i in range(job_num):    # i为工件编号
        job_list = J[i]              # job为该工件的工序列表
        for j in range(len(job_list)):       # j为工序编号
            machine_list = job_list[j]  # i工件的第j个工序的可选加工机器列表
            MS.append(np.random.randint(len(machine_list)))
    return MS


def createInd(n, J, P, split_list=None):
    """
    GLR机器选择方法
    GS:全局选择策略
    LS:局部选择策略
    RS:随机选择策略
    split_list 为三种策略的数量矩阵,如
    split_list = [10, 10, 20],意为GS、LS各10个个体,RS随机20个个体
    """
    if split_list is None:
        split_list = [10, 10, 20]
    pop = []
    gs = GS(n, J, P)
    ls = LS(n, J, P)
    OS = []
    for i in range(len(J)):
        for _ in range(len(J[i])):
            OS.append(i)
    for _ in range(split_list[0]):
        pop.append(gs + np.random.permutation(OS).tolist())
    for _ in range(split_list[1]):
        pop.append(ls + np.random.permutation(OS).tolist())
    for _ in range(split_list[2]):
        pop.append(RS(n, J, P) + np.random.permutation(OS).tolist())
    return pop


def decode(J, P, s, n):
    """
    function:
    JSP解码函数,用于计算C_max和生成甘特图。

    parameter:
    - J: 机器顺序矩阵
    - P: 加工时间矩阵
    - s: 待解码的序列。
    - n: 机器数

    return:
    - T: 甘特图矩阵。
    - M: 工件排列矩阵。
    - C: 完工时间矩阵。
    """
    job_num = len(J)        # 工件数
    process_num = 0         # 总工序数
    machine_list = []
    max_process_num = 0     # 最大工序数
    # print(J)
    # print(s)
    # machine_list = [item for sublist1 in J for item in sublist1]
    for i in range(job_num):
        machine_list_by_process = s[:len(J[i])] if max_process_num == 0 else s[process_num:process_num+len(J[i])]
        # print(f'i:{i}, list:{machine_list_by_process}, J[i]:{len(J[i])}')
        max_process_num = max(max_process_num, len(J[i]))       # 计算最大工序数
        machine_list.append(machine_list_by_process)
        process_num += len(J[i])    # 计算总工序数
    s = s[process_num:]      # 更新s为后半部分OS
    # print(machine_list, s, process_num, max_process_num)
    # print(f'machine_list:{machine_list}')
    T = [[[0]] for _ in range(n)]
    C = np.zeros((job_num, max_process_num))
    k = np.zeros(job_num, dtype=int)
    # print(s)
    # print(machine_list)
    # print(len(machine_list))
    for job in s:
        # print(f'job:{job}')
        # print(f'm list:{machine_list[job]}')
        machine_index = machine_list[job][k[job]]       # 机器编号
        # print(f'第{job}个工件的第{k[job]}个工序,机器编号是{machine_index}')
        # print(J[job])
        # print(J[job][k[job]])
        machine = J[job][k[job]][machine_index]                 # 机器号
        # machine = J[job, k[job]] - 1
        process_time = P[job][k[job]][machine_index]
        # process_time = P[job, k[job]]
        last_job_finish = C[job, k[job] - 1] if k[job] > 0 else 0

        # 寻找机器上的第一个合适空闲时间段
        # print(f'T:{T},machine:{machine}')
        start_time = max(last_job_finish, T[machine][-1][-1])  # 默认在最后一个任务后开始
        insert_index = len(T[machine])  # 默认插入位置在末尾
        for i in range(1, len(T[machine])):
            gap_start = max(T[machine][i - 1][-1], last_job_finish)
            gap_end = T[machine][i][0]
            if gap_end - gap_start >= process_time:
                start_time = gap_start  # 找到合适的起始时间
                insert_index = i  # 更新插入位置
                break
        # print(start_time, process_time)
        end_time = start_time + process_time
        # print(C)
        C[job, k[job]] = end_time
        T[machine].insert(insert_index, [start_time, job, k[job], end_time])
        k[job] += 1

    return T, C


def drawGantt(timeList):
    T = timeList.copy()
    # 创建一个新的图形
    plt.rcParams['font.sans-serif'] = ['SimHei']
    fig, ax = plt.subplots(figsize=(10, 6))

    # 颜色映射字典,为每个工件分配一个唯一的颜色
    color_map = {}
    for machine_schedule in T:
        for task_data in machine_schedule[1:]:
            job_idx, operation_idx = task_data[1], task_data[2]
            if job_idx not in color_map:
                # 为新工件分配一个随机颜色
                color_map[job_idx] = (random.random(), random.random(), random.random())

    # 遍历机器
    for machine_idx, machine_schedule in enumerate(T):
        for task_data in machine_schedule[1:]:
            start_time, job_idx, operation_idx, end_time = task_data
            color = color_map[job_idx]  # 获取工件的颜色

            # 绘制甘特图条形,使用工件的颜色
            ax.barh(machine_idx, end_time - start_time, left=start_time, height=0.4, color=color)

            # 在色块内部标注工件-工序
            label = f'{job_idx}-{operation_idx}'
            ax.text((start_time + end_time) / 2, machine_idx, label, ha='center', va='center', color='white',
                    fontsize=10)

    # 设置Y轴标签为机器名称
    ax.set_yticks(range(len(T)))
    ax.set_yticklabels([f'Machine {i+1}' for i in range(len(T))])

    # 设置X轴标签
    plt.xlabel("时间")

    # 添加标题
    plt.title("FJSP问题甘特图")

    # 创建图例,显示工件颜色
    legend_handles = []
    for job_idx, color in color_map.items():
        legend_handles.append(plt.Rectangle((0, 0), 1, 1, color=color, label=f'Job {job_idx}'))
    plt.legend(handles=legend_handles, title='工件')

    # # 显示图形
    plt.show()


def choice(fitness, k=3, pool=40):
    """
    fitness: 适应度,根据适应度做竞标赛
    k: 每次比较的个数
    pool: 交叉池大小
    """
    n = len(fitness)
    choice_index = []
    for _ in range(pool):
        random_indices = random.sample(range(n), k)
        f_values = [fitness[i] for i in random_indices]
        min_f_value = min(f_values)
        choice_index.append(random_indices[f_values.index(min_f_value)])
    return choice_index


def cross_MS(A, B):
    job_num = len(A)
    random_numbers = random.sample(list(range(job_num)), 2)
    # random_numbers = [0,4]
    rl, rr = min(random_numbers), max(random_numbers)
    afinal = B[:rl] + A[rl:rr+1] + B[rr+1:]
    bfinal = A[:rl] + B[rl:rr+1] + A[rr+1:]
    return afinal, bfinal


def cross_OS(A, B):
    job_id = list(set(A))
    job_num = len(A)
    # 确保抽取的数量不为0且不等于列表长度
    while True:
        num_to_extract = random.randint(1, len(job_id) - 1)  # 随机抽取的数量,不能为0和等于列表长度
        if num_to_extract > 0 and num_to_extract < len(job_id):
            break
    # 随机抽取元素,S1集合
    S1 = random.sample(job_id, num_to_extract)
    # for list A
    afinal = [None for _ in range(job_num)]
    temp_B = [item for item in B if item not in S1]
    k = 0
    for i in range(job_num):
        if A[i] in S1:
            afinal[i] = A[i]
        else:
            afinal[i] = temp_B[k]
            k += 1
    # for list B
    bfinal = [None for _ in range(job_num)]
    temp_A = [item for item in A if item not in S1]
    k = 0
    for i in range(job_num):
        if B[i] in S1:
            bfinal[i] = B[i]
        else:
            bfinal[i] = temp_A[k]
            k += 1
    return afinal, bfinal


def cross(A, B):
    job_num_all = int(len(A)/2)
    MS_A = A[:job_num_all]
    OS_A = A[job_num_all:]
    MS_B = B[:job_num_all]
    OS_B = B[job_num_all:]
    MS_A, MS_B = cross_MS(MS_A, MS_B)
    OS_A, OS_B = cross_OS(OS_A, OS_B)
    return MS_A + OS_A, MS_B + OS_B


def mutation_MS(A, P):
    process_num = len(A)
    process_time = [item for sublist1 in P for item in sublist1]    # 拉平P
    r = np.random.randint(process_num)
    random_selection = random.sample(list(range(process_num)), r)
    for i in random_selection:
        A[i] = process_time[i].index(min(process_time[i]))
    return A


def mutation_OS(Ind):
    '''
    function: mutation
    content: mutationg a individual with INV approach, then return the mutated individual.
        revers a random sequence of gens in an individual
    '''
    A = Ind.copy()
    n = len(A)      # 工件数
    index1, index2 = random.sample(range(n), 2)     # 随即两个数
    rl, rr = max(index1, index2)+1, min(index1, index2)     # 为了避免[x:x]的索引为空,max需要+1
    A[rr: rl] = A[rr: rl][::-1]
    return A


def mutation(s, P):
    job_num_all = int(len(s) / 2)
    MS = s[:job_num_all]
    OS = s[job_num_all:]
    return mutation_MS(MS, P) + mutation_OS(OS)


def load_data(path):
    # 从文件中读取数据
    with open(path+".fjs", "r") as file:
        lines = file.readlines()

    # 解析第一行,获取工件数和机器数
    first_line = lines[0].strip().split()
    num_jobs = int(first_line[0])
    num_machines = int(first_line[1])

    # 初始化加工机器矩阵J和加工时间矩阵P
    J = []
    P = []

    # 解析数据行,动态获取工序数并构建J和P矩阵
    for line in lines[1:]:
        # print(line)
        data = line.strip().split()
        if not data:
            continue  # 跳过空行
        # 第一行数据,获取工序数
        num_operations = int(data[0])
        # print(f'工序:{num_operations}')
        data = data[1:]
        job = []
        processing_time = []
        l = 0
        while l < num_operations:
            # print(f'l:{l} data:{data}, num:{num_operations}')
            process_num = int(data[0])
            machine_list = []
            process_list = []
            data = data[1:]
            # print(f'data{data} process_num{process_num}')
            for i in range(process_num):
                machine_list.append(int(data[i*2]) - 1)        # 机器从0开始编号
                process_list.append(int(data[i*2+1]))
            job.append(machine_list)
            processing_time.append(process_list)
            data = data[i*2+2:]
            l += 1
        J.append(job)
        P.append(processing_time)

    # # 打印结果
    # print("工件数:", num_jobs)
    # print("机器数:", num_machines)
    # print("加工机器矩阵J:", J)
    # print("加工时间矩阵P:", P)
    return J, P, num_machines


if __name__ == "__main__":
    J, P, machine_num = load_data('Mk10')
    # print(J, P, machine_num)
    # J = [[[0, 1, 2, 3, 4], [1, 3]],
    #      [[0, 2, 4], [0, 1, 2], [1, 2, 3, 4]]]
    #
    # P = [[[2, 6, 5, 3, 4], [8, 4]],
    #      [[3, 6, 5], [4, 6, 5], [7, 11, 5, 8]]]
    #
    # machine_num = 5


    pop = createInd(machine_num, J, P, [10, 10, 20])
    pop_size = 40
    # print(pop[0])
    # print(decode(J, P, pop[0], machine_num))
    fitness = [decode(J, P, i, machine_num)[1].max() for i in pop]
    # 初始化最值指标
    best_index = fitness.index(min(fitness))
    best_ind = pop[best_index].copy()
    Cmax = fitness[best_index]
    best_T = decode(J, P, best_ind, machine_num)[0]
    g, gen = 0, 100
    chistory = [Cmax]
    while g < gen:
        g += 1
        # 父代与选择的个体之间进行交叉
        choice_index = choice(fitness, 3, pool=pop_size)
        new_pop = [pop[i] for i in choice_index]
        l = 0
        while l < pop_size / 2:
            if np.random.rand() < 0.7:
                new_pop[l], new_pop[l+1] = cross(new_pop[l], new_pop[l+1])
            if np.random.rand() < 0.005:
                new_pop[l] = mutation(new_pop[l], P)
            if np.random.rand() < 0.005:
                new_pop[l+1] = mutation(new_pop[l+1], P)
            l += 2
        pop = new_pop
        # 计算种群信息
        fitness = [decode(J, P, i, machine_num)[1].max() for i in pop]

        best_index_temp = fitness.index(min(fitness))
        Cmax_temp = fitness[best_index]
        if Cmax_temp < Cmax:
            Cmax = Cmax_temp
            best_ind = pop[best_index].copy()
            best_T = decode(J, P, best_ind, machine_num)[0]
        chistory.append(Cmax)
    print(f'Cmax:{Cmax}')
    plt.plot(chistory)
    drawGantt(best_T)

遗传算法收敛图:

mk01数据集甘特图:

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
粒子群柔性作业车间调度(Particle Swarm Optimization (PSO) for Flexible Job Shop Scheduling)是一种优化算法,通过模拟鸟群中的行为来解决作业车间调度问题。 在这个问题中,有多个作业(jobs)需要在不同的设备(machines)上进行处理。每个作业有一系列的操作(operations),每个操作需要在特定的设备上进行处理,并具有预定的处理时间。 粒子群柔性作业车间调度算法的Matlab代码如下: ```matlab function [best_sequence, best_fitness] = PSO_FJSP(jobs, machines, operations, swarm_size, max_iterations) % 初始化粒子群 particles = initialize_particles(jobs, machines, swarm_size); % 初始化全局最优解 global_best_fitness = Inf; global_best_sequence = []; % 迭代更新粒子群 for iter = 1:max_iterations % 更新每个粒子的速度和位置 particles = update_velocity_position(particles, global_best_sequence); % 计算每个粒子的适应度 for i = 1:swarm_size fitness = calculate_fitness(particles(i).sequence, jobs, machines, operations); % 更新个体最优解 if fitness < particles(i).best_fitness particles(i).best_fitness = fitness; particles(i).best_sequence = particles(i).sequence; end % 更新全局最优解 if fitness < global_best_fitness global_best_fitness = fitness; global_best_sequence = particles(i).sequence; end end end % 输出最优解 best_sequence = global_best_sequence; best_fitness = global_best_fitness; end ``` 以上是粒子群柔性作业车间调度的简单实现,代码中定义了初始化粒子群、更新速度和位置、计算适应度等函数。通过调用`PSO_FJSP`函数,可以得到最优的作业调度序列(`best_sequence`)以及对应的适应度值(`best_fitness`)。 需要注意的是,以上代码只是一个简单的实现,实际应用中可能需要根据具体的问题进行参数调整和性能优化。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值