遗传算法车间调度代码详解

PS:本文章对于基于遗传算法的传统作业车间调度问题的求解(Job-shop scheduling problem based on genetic algorithm)_遗传算法求解调度问题仿真实验-CSDN博客

中提到的代码进行详细解释,仅作为学习记录

(1)编码

% 初始化一个空列表
initial = [];

% 根据作业的步骤生成初始序列
for i = 1 : num_of_jobs
    for j = 1 : number_of_machines
        % 将作业索引 i 添加到 initial 列表中
        initial = [initial i];
    end
end

% 生成包含随机基因的种群染色体
for i = 1 : PopSize
    % 使用 randperm 函数对 initial 列表进行随机排列,并将结果赋值给种群矩阵的当前行
    population(i, :) = initial(randperm(length(initial(:))));
end

代码解释:

  1. initial=[];:初始化一个空列表initial,用于存储作业的步骤。

  2. for i = 1:num_of_jobs:外层循环,遍历作业的步骤。

  3. for j = 1:number_of_machines:内层循环,遍历每个作业在机器上的执行顺序。

  4. initial=[initial i];:将当前作业的索引i添加到initial列表中。这样做的目的是生成一个基本的作业顺序,其中每个作业在每个机器上执行一次。在每次迭代中,将作业索引添加到initial列表。

  5. 外层循环结束后,initial列表中将包含按照作业步骤顺序生成的元素。

  6. for i = 1:PopSize:循环生成种群。

  7. population(i,:) = initial(randperm(length(initial(:))));:对initial列表进行随机排列,并将结果赋值给种群矩阵的当前行。randperm(length(initial(:)))生成一个长度与initial列表相同的随机排列索引,然后使用这些索引对initial列表进行重新排列。这样得到的结果就是一个随机的染色体,即一种作业顺序的排列。

  8. 最终,population矩阵的每一行代表一个随机生成的染色体,即一种作业顺序的排列。这个种群矩阵将作为遗传算法的初始种群,用于后续的进化和优化过程。

(2)解码

function [Jobs, Cmax, MachineList, ST, PT] = SemiActiveDecoding(T, Chromosome)
% INPUT:
% T -- 输入矩阵:
% 每个实例由一行描述组成,一行包含作业数量和机器数量,然后每个作业占用一行,
% 列出每个作业的每个步骤的机器编号和处理时间。机器从0开始编号。
% Chromosome -- 要解码的染色体
% OUTPUT:
% Jobs -- 作业序列
% Cmax -- 最大完成时间
% MachineList -- 与染色体对应的机器序列
% ST -- 染色体中每个作业步骤的开始时间
% PT -- 染色体中每个作业步骤的处理时间

    % +++++++++++++++++++++++++++++
    %  Fisher和Thompson 6x6实例,备用名称(mt06)
    %  6 6
    %  2  1  0  3  1  6  3  7  5  3  4  6
    %  1  8  2  5  4 10  5 10  0 10  3  4
    %  2  5  3  4  5  8  0  9  1  1  4  7
    %  1  5  0  5  2  5  3  3  4  8  5  9 
    %  2  9  1  3  4  5  5  4  0  3  3  1
    %  1  3  3  3  5  9  0 10  4  4  2  1
    %  +++++++++++++++++++++++++++++

%% start
[num_of_jobs, number_of_machines] = size(T);
%% 在这个例子中,每个作业有6个步骤,
%% 每个步骤包含机器编号和处理时间。因此,
%%总共有12个列,其中6列是机器编号,6列是处理时间。
number_of_machines = number_of_machines / 2;  % 作业和机器的数量
Jobs = unique(Chromosome);
StepList = [];  % 所有基因的步骤列表
MachineList = [];
DecodedGenes = [];
ST = [];
PT = [];
len_of_chromosome = num_of_jobs * number_of_machines;

%% 计算了 MachineList 和 PT,即机器序列和处理时间。
for index = 1:len_of_chromosome
    DecodedGenes = [DecodedGenes Chromosome(index)];
    postion = length(find(DecodedGenes == Chromosome(index)));
    StepList = [StepList postion];
    pos1 = postion * 2 - 1;
    pos2 = postion * 2;
    MachineList = [MachineList T(Chromosome(index), pos1)];
    PT = [PT T(Chromosome(index), pos2)];
end

%% 计算 ST,即作业的开始时间
Machines = unique(MachineList);
steps = unique(StepList);

job_start_time = cell(num_of_jobs, 1);
job_end_time = cell(num_of_jobs, 1);
machine_start_time = cell(number_of_machines, 1);
machine_end_time = cell(number_of_machines, 1);
machine_state = zeros(1, number_of_machines);  % 0--FirstWork; 1--NotFirst

for index = 1:len_of_chromosome
    job = Chromosome(index);
    machine = MachineList(index);
    pt = PT(index);
    step = StepList(index);
    pos_m = find(Machines == machine);
    pos_j = find(Jobs == job);
    if step == 1  % 第一个步骤,不考虑同一作业步骤之间的约束
        if machine_state(pos_m) == 0  % 机器首次使用
            job_start_time{pos_j} = [0, pos_m];
            job_end_time{pos_j} = [job_start_time{pos_j}(1) + pt, pos_m];
        else
            job_start_time{pos_j} = [machine_end_time{pos_m}(1), pos_m];
            job_end_time{pos_j} = [job_start_time{pos_j}(1) + pt, pos_m];
        end
    else
        if machine_state(pos_m) == 0  % 机器首次使用
            job_start_time{pos_j} = [job_end_time{pos_j}(1), pos_m];
            job_end_time{pos_j} = [job_start_time{pos_j}(1) + pt, pos_m];
        else
            job_start_time{pos_j} = [max(machine_end_time{pos_m}(1), job_end_time{pos_j}(1)), pos_m];
            job_end_time{pos_j} = [job_start_time{pos_j}(1) + pt, pos_m];
        end
    end
    machine_start_time{pos_m} = [job_start_time{pos_j}(1)];
    machine_end_time{pos_m} = [job_end_time{pos_j}(1)];
    machine_state(pos_m) = 1;
    ST = [ST, job_start_time{pos_j}(1)];
end

%% 计算 Cmax,即最大完成时间
end_time = cell2mat(job_end_time);
Cmax = max(end_time(:, 1));

end
  1. 获取输入参数:

    • T:输入矩阵,描述了作业和机器的相关信息。每个实例都由一行描述组成,接下来一行包含作业数和机器数的信息,然后是每个作业的描述,包括每个步骤的机器编号和处理时间。
    • Chromosome:待解码的染色体。
  2. 初始化变量:

    • num_of_jobs:作业数量
    • number_of_machines:机器数量
    • Jobs:唯一的作业列表
    • StepList:每个基因的步骤列表
    • MachineList:每个基因的机器列表
    • DecodedGenes:已解码的基因序列
    • ST:每个作业步骤的开始时间
    • PT:每个作业步骤的持续时间
    • len_of_chromosome:染色体长度,即基因数量
  3. 计算MachineListPT
    对于染色体中的每个基因,将其添加到DecodedGenes中,并计算其在DecodedGenes中的位置。然后根据位置计算步骤在T矩阵中的索引,并将对应的机器和持续时间添加到MachineListPT中。

  4. 计算ST

    • 初始化变量:
      • Machines:唯一的机器列表
      • steps:唯一的步骤列表
      • job_start_timejob_end_time:用于存储每个作业的开始时间和结束时间的单元格数组
      • machine_start_timemachine_end_time:用于存储每个机器的开始时间和结束时间的单元格数组
      • machine_state:机器状态的数组,用于跟踪机器是否是第一次使用
    • 遍历染色体中的每个基因:
      • 获取作业、机器、持续时间和步骤信息
      • 查找机器和作业在唯一列表中的位置
      • 根据步骤是否为第一步骤,计算作业的开始时间和结束时间
      • 更新机器的开始时间和结束时间,以及机器状态
      • 将作业的开始时间添加到ST
  5. 计算Cmax

    • 将所有作业的结束时间提取到一个矩阵中
    • 计算最大结束时间,即最大完成时间
  6. 返回结果:

    • Jobs:作业序列
    • Cmax:最大完成时间
    • MachineList:机器序列
    • ST:作业步骤的开始时间
    • PT:作业步骤的持续时间

详细代码解释:

部分1:

for index = 1:len_of_chromosome
    DecodedGenes = [DecodedGenes Chromosome(index)];
    position = length(find(DecodedGenes == Chromosome(index)));
    StepList = [StepList position];
    pos1 = position * 2 - 1;
    pos2 = position * 2;
    MachineList = [MachineList T(Chromosome(index), pos1)];
    PT = [PT T(Chromosome(index), pos2)];
end
  1. for循环迭代染色体中的每个基因(index从1到len_of_chromosome)。
  2. 将当前基因Chromosome(index)添加到DecodedGenes列表中,以构建解码后的基因序列。
  3. 计算当前基因在DecodedGenes中的位置,即该基因在已解码基因序列中的出现次数。使用find函数找到与当前基因相等的元素,然后使用length函数计算找到的元素数量。
  4. 将当前基因在已解码基因序列中的位置(即出现次数)添加到StepList列表中,以记录每个基因的位置信息。
  5. 根据基因在已解码基因序列中的位置计算机器编号在输入矩阵T中的索引。将pos1设置为当前位置乘以2减去1,将pos2设置为当前位置乘以2。
  6. 从输入矩阵T中获取对应的机器编号和处理时间。使用T(Chromosome(index), pos1)获取机器编号,并将其添加到MachineList列表中。使用T(Chromosome(index), pos2)获取处理时间,并将其添加到PT列表中。

部分2:

%% Caculate ST
Machines = unique(MachineList);
steps = unique(StepList);
  1. 代码中使用unique函数获取MachineList中的唯一机器编号,并将结果存储在Machines变量中。这样做是为了确定在解码后的基因序列中有多少台不同的机器参与。
  2. 接下来,使用unique函数获取StepList中的唯一步骤编号,并将结果存储在steps变量中。这样做是为了确定在解码后的基因序列中有多少个不同的步骤。

部分3:

job_start_time = cell(num_of_jobs,1);
job_end_time = cell(num_of_jobs,1);
machine_start_time = cell(number_of_machines,1);
machine_end_time = cell(number_of_machines,1);
machine_state = zeros(1,number_of_machines);
  1. 创建一个大小为num_of_jobs的cell数组job_start_time,用于存储每个作业的开始时间。
  2. 创建一个大小为num_of_jobs的cell数组job_end_time,用于存储每个作业的结束时间。
  3. 创建一个大小为number_of_machines的cell数组machine_start_time,用于存储每台机器的开始时间。
  4. 创建一个大小为number_of_machines的cell数组machine_end_time,用于存储每台机器的结束时间。
  5. 创建一个大小为1xnumber_of_machines的零矩阵machine_state,用于记录每台机器的状态。其中0表示该机器是第一次执行作业,1表示该机器不是第一次执行作业。

部分4:

for index = 1:len_of_chromosome
    job = Chromosome(index);
    machine = MachineList(index);
    pt = PT(index);
    step = StepList(index);
    pos_m = find(Machines==machine);
    pos_j = find(Jobs==job);
  • for 循环遍历基因序列中的每个基因。
  • job 变量存储当前基因对应的作业编号。
  • machine 变量存储当前基因对应的机器编号。
  • pt 变量存储当前基因对应的处理时间。
  • step 变量存储当前基因对应的步骤编号。
  • pos_m 变量记录机器编号在 Machines 数组中的位置。
  • pos_j 变量记录作业编号在 Jobs 数组中的位置。
if step==1
    if machine_state(pos_m)==0
        job_start_time{pos_j}=[0,pos_m];
        job_end_time{pos_j}=[job_start_time{pos_j}(1)+pt,pos_m];
    else
        job_start_time{pos_j}=[machine_end_time{pos_m}(1),pos_m];
        job_end_time{pos_j}=[job_start_time{pos_j}(1)+pt,pos_m];
    end
else
    if machine_state(pos_m)==0
        job_start_time{pos_j}=[job_end_time{pos_j}(1),pos_m];
        job_end_time{pos_j}=[job_start_time{pos_j}(1)+pt,pos_m];
    else
        job_start_time{pos_j}=[max(machine_end_time{pos_m}(1),job_end_time{pos_j}(1)),pos_m];
        job_end_time{pos_j}=[job_start_time{pos_j}(1)+pt,pos_m];
    end       
end
  • 如果 step 等于1,表示当前基因是作业的第一个步骤,不考虑作业内部步骤之间的约束。
    • 如果机器状态 machine_state 在位置 pos_m 上为0,表示该机器是第一次被使用。
      • 将作业的开始时间设置为 [0, pos_m]
      • 将作业的结束时间设置为 [job_start_time{pos_j}(1) + pt, pos_m]
    • 否则,表示该机器已经被使用过。
      • 将作业的开始时间设置为 [machine_end_time{pos_m}(1), pos_m]
      • 将作业的结束时间设置为 [job_start_time{pos_j}(1) + pt, pos_m]
  • 否则,表示当前基因是作业的其他步骤。
    • 如果机器状态 machine_state 在位置 pos_m 上为0,表示该机器是第一次被使用。
      • 将作业的开始时间设置为 [job_end_time{pos_j}(1), pos_m]
      • 将作业的结束时间设置为 [job_start_time{pos_j}(1) + pt, pos_m]
    • 否则,表示该机器已经被使用过。
      • 将作业的开始时间设置为 [max(machine_end_time{pos_m}(1), job_end_time{pos_j}(1)), pos_m]
      • 将作业的结束时间设置为 [job_start_time{pos_j}(1) + pt, pos_m]
machine_start_time{pos_m}= [job_start_time{pos_j}(1)];
machine_end_time{pos_m} = [job_end_time{pos_j}(1)]; 
machine_state(pos_m)=1;
ST=[ST, job_start_time{pos_j}(1)];
end
  • 更新机器的开始时间 machine_start_time 为对应作业的开始时间的第一个元素。
  • 更新机器的结束时间 machine_end_time 为对应作业的结束时间的第一个元素。
  • 将机器状态 machine_state 在位置 pos_m 上设置为1,表示该机器已被使用过。
  • 将作业的开始时间的第一个元素添加到 ST 数组中。
  • 结束循环。

以上代码段的目的是根据基因序列中的信息计算每个作业的开始时间和结束时间,以及每台机器的开始时间和结束时间。根据不同的步骤和机器状态,更新相应的时间记录。

部分5:

end_time = cell2mat(job_end_time);
  • job_end_time这个cell数组转换为矩阵end_timejob_end_time中存储了每个作业的结束时间,每个元素是一个包含开始时间和机器编号的向量。通过cell2mat函数,将这些向量转换为矩阵形式。
Cmax = max(end_time(:,1));
  • 从矩阵end_time中选择所有行的第一列,即所有作业的结束时间。
  • 通过max函数,找到这些结束时间中的最大值。
  • 将最大值赋给变量Cmax,表示任务调度中的最大完成时间。
  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CTGU-Yoghurt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值