柔性作业车间调度问题-启发求解方法

问题描述

柔性作业车间问题可描述为:每一待加工工件包含一道或一道以上工序,每个工件的工序 顺序都是已知的,每道工序可以在一台及以上的机器上完成加工, 加工的时间会因为所选择的加工机器不同而变得不同。 调度方案需要确定工序的加工顺序和机器的选择,从而使得整个调度系统的各指标达到最优。
加工过程需满足以下条件:
(1)工件工序只能在可加工设备上进行加工
(2)一台设备同一时间段只能对一个工件工序进行加工
(3)工件工序开始加工后无法停止
(4)工件下一工序的开始时间大于等于上一工序的结束时间,即工件工序具备加工次序

工件数据

仿真数据来源于文献:[1]高尚,李荣平.改进NSGA-Ⅱ求解多目标柔性作业车间调度问题[J].河北企业,2022(04):70-72.DOI:10.19885/j.cnki.hbqy.2022.04.021.
在这里插入图片描述

最早开始时间启发策略

最早开始时间启发策略是指在工件工序加工过程中,依据工件工序在各个设备上的最早的开始加工时间为依据将工件工序分配到设备进行加工。
实现代码:

/**
     * 启发策略-最早开始时间
     */
    private void EST(){
        while (true) {
            //遍历工件
            for (int i = 0; i < data.workId.length; i++) {
                //选取工序i的剩余第一个工序
                if (workProcess.get(i).size() != 0) {
                    //System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
                    //随机生成设备遍历顺序
                    int[] orderArr = new int[data.deviceId.length];
                    for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
                    shuffle(orderArr);
                    //找到开始时间最短的机器设备
                    int deviceIndex = data.deviceId.length;
                    double deviceTime = Double.MAX_VALUE;
                    //随机遍历机器
                    for (int j = 0; j < data.deviceId.length; j++) {
                        //工序只能在可加工设备上进行加工
                        if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
                            if (workResult.get(orderArr[j]).size() == 0) {
                                //下一工序的开始时间大于等于上一工序的结束时间
                                if (workProcess.get(i).get(0) == 1) {
                                    //第一个工序
                                    deviceTime = 0;
                                    deviceIndex = orderArr[j];
                                    //System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
                                    break;
                                }
                            } else {
                                if (workProcess.get(i).get(0) == 1) {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
                                        deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
                                        deviceIndex = orderArr[j];
                                    }
                                } else {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
                                            deviceIndex = orderArr[j];
                                        }
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1;
                                            deviceIndex = orderArr[j];
                                        }
                                    }
                                }
                            }
                        }
                        //System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
                    }
                    //更新工件信息
                    if (deviceIndex != data.deviceId.length) {
                        shop.workId = i + 1;
                        shop.workProcess = workProcess.get(i).get(0);
                        shop.deviceId = deviceIndex + 1;
                        shop.startTime = deviceTime;
                        startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
                        //System.out.println(i + "\t" + (workProcessTemp.get(i).get(0) - 1) + "\t" + deviceIndex);
                        shop.endTime = shop.startTime + data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];
                        endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
                        //工件信息加入结果列表
                        workResult.get(deviceIndex).add(shop.clone());
                        //删除该工序
                        workProcess.get(i).remove(0);
                    }
                }
            }
            //所有工序分配完毕时,结束
            boolean stopCondition = true;
            for (int i = 0; i < data.workId.length; i++) {
                if (workProcess.get(i).size() != 0) {
                    stopCondition = false;
                    break;
                }
            }
            if (stopCondition) break;
        }
        printResult(workResult,endTime);
    }

启发求解结果:
在这里插入图片描述

最早开始时间启发策略改进首工序分配

在使用最早开始时间启发策略过程中,采用随机分配工序的方式到设备,并且一旦设备满足加工条件,就将工件分配到该设备进行加工。其结果也可以发现,总会存在个别设备未被分配加工任务,导致最大的工件完工时间较长。
在这里,采用匈牙利算法对首工序进行设备分配,其余工序同样采用随机分配的方式。当然,若是有兴趣的研究者可以逐次将下一工序进行分配。
实现代码:

/**
     * 贪婪启发策略-最早开始时间
     * 匈牙利算法分配第一工序和设备
     */
    private void GEST(){
        //第一个工序分配
        int[] assignResult=shopAssign(data.ProcessTime);
        //分配第一个工序
        for(int i=0;i<assignResult.length;i++){
            int deviceIndex = data.deviceId.length;
            double deviceTime = Double.MAX_VALUE;
            if (workProcess.get(i).size() != 0){
                if (workResult.get(assignResult[i]-1).size() == 0){
                    deviceTime = 0;
                    deviceIndex = assignResult[i]-1;
                }
                else{
                    deviceTime = workResult.get(assignResult[i]-1).get(workResult.get(assignResult[i]-1).size() - 1).endTime+1;
                    deviceIndex = assignResult[i]-1;
                }
            }
            if (deviceIndex != data.deviceId.length) {
                shop.workId = i + 1;
                shop.workProcess = workProcess.get(i).get(0);
                shop.deviceId = deviceIndex + 1;
                shop.startTime = deviceTime;
                startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
                shop.endTime = shop.startTime + data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];
                endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
                workResult.get(deviceIndex).add(shop.clone());
                workProcess.get(i).remove(0);
            }
        }
        //分配其余工序
        while (true) {
            //遍历工件
            for (int i = 0; i < data.workId.length; i++) {
                //选取工序i的剩余第一个工序
                if (workProcess.get(i).size() != 0) {
                    //System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
                    //随机生成设备遍历顺序
                    int[] orderArr = new int[data.deviceId.length];
                    for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
                    shuffle(orderArr);
                    //找到开始时间最短的机器设备
                    int deviceIndex = data.deviceId.length;
                    double deviceTime = Double.MAX_VALUE;
                    //随机遍历机器
                    for (int j = 0; j < data.deviceId.length; j++) {
                        //工序只能在可加工设备上进行加工
                        if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
                            if (workResult.get(orderArr[j]).size() == 0) {
                                //下一工序的开始时间大于等于上一工序的结束时间
                                if (workProcess.get(i).get(0) == 1) {
                                    //第一个工序
                                    deviceTime = 0;
                                    deviceIndex = orderArr[j];
                                    //System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
                                    break;
                                }
                            } else {
                                if (workProcess.get(i).get(0) == 1) {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
                                        deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
                                        deviceIndex = orderArr[j];
                                    }
                                } else {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
                                            deviceIndex = orderArr[j];
                                        }
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1;
                                            deviceIndex = orderArr[j];
                                        }
                                    }
                                }
                            }
                        }
                        //System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
                    }
                    //更新工件信息
                    if (deviceIndex != data.deviceId.length) {
                        shop.workId = i + 1;
                        shop.workProcess = workProcess.get(i).get(0);
                        shop.deviceId = deviceIndex + 1;
                        shop.startTime = deviceTime;
                        startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
                        //System.out.println(i + "\t" + (workProcessTemp.get(i).get(0) - 1) + "\t" + deviceIndex);
                        shop.endTime = shop.startTime + data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];
                        endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
                        //工件信息加入结果列表
                        workResult.get(deviceIndex).add(shop.clone());
                        //删除该工序
                        workProcess.get(i).remove(0);
                    }
                }
            }
            //所有工序分配完毕时,结束
            boolean stopCondition = true;
            for (int i = 0; i < data.workId.length; i++) {
                if (workProcess.get(i).size() != 0) {
                    stopCondition = false;
                    break;
                }
            }
            if (stopCondition) break;
        }
        printResult(workResult,endTime);
    }

运行结果发现,工件在设备上的分配更为有序。
在这里插入图片描述

最早结束时间启发策略

与最早开始时间相同,最早结束时间启发策略是指在工件工序加工过程中,依据工件工序在各个设备上的最早的结束加工时间为依据将工件工序分配到设备进行加工。
实现代码:

/**
     * 启发策略-最早结束时间
     * 随机分配工序
     */
    private void EET(){
        while (true) {
            //遍历工件
            for (int i = 0; i < data.workId.length; i++) {
                //选取工序i的剩余第一个工序
                if (workProcess.get(i).size() != 0) {
                    //System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
                    //随机生成设备遍历顺序
                    int[] orderArr = new int[data.deviceId.length];
                    for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
                    shuffle(orderArr);
                    //找到开始时间最短的机器设备
                    int deviceIndex = data.deviceId.length;
                    double deviceTime = Double.MAX_VALUE;
                    //随机遍历机器
                    for (int j = 0; j < data.deviceId.length; j++) {
                        //工序只能在可加工设备上进行加工
                        if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
                            if (workResult.get(orderArr[j]).size() == 0) {
                                //下一工序的开始时间大于等于上一工序的结束时间
                                if (workProcess.get(i).get(0) == 1) {
                                    //第一个工序
                                    deviceTime = data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                    deviceIndex = orderArr[j];
                                    break;
                                }
                            } else {
                                if (workProcess.get(i).get(0) == 1) {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]] < deviceTime) {
                                        deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                        deviceIndex = orderArr[j];
                                    }
                                } else {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]]< deviceTime) {
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                            deviceIndex = orderArr[j];
                                        }
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                            deviceIndex = orderArr[j];
                                        }
                                    }
                                }
                            }
                        }
                        //System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
                    }
                    //更新工件信息
                    if (deviceIndex != data.deviceId.length) {
                        shop.workId = i + 1;
                        shop.workProcess = workProcess.get(i).get(0);
                        shop.deviceId = deviceIndex + 1;
                        shop.endTime = deviceTime;
                        endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
                        shop.startTime = shop.endTime - data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];;
                        startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
                        //工件信息加入结果列表
                        workResult.get(deviceIndex).add(shop.clone());
                        //删除该工序
                        workProcess.get(i).remove(0);
                    }
                }
            }
            //所有工序分配完毕时,结束
            boolean stopCondition = true;
            for (int i = 0; i < data.workId.length; i++) {
                if (workProcess.get(i).size() != 0) {
                    stopCondition = false;
                    break;
                }
            }
            if (stopCondition) break;
        }
        printResult(workResult,endTime);
    }

启发求解结果:
在这里插入图片描述

最早结束时间启发策略改进首工序分配

/**
     * 贪婪启发策略-最早结束时间
     * 匈牙利算法分配第一工序和设备
     */
    private void GEET(){
        //第一个工序分配
        int[] assignResult=shopAssign(data.ProcessTime);
        //分配第一个工序
        for(int i=0;i<assignResult.length;i++){
            int deviceIndex = data.deviceId.length;
            double deviceTime = Double.MAX_VALUE;
            if (workProcess.get(i).size() != 0){
                if (workResult.get(assignResult[i]-1).size() == 0){
                    deviceTime = data.ProcessTime[i][workProcess.get(i).get(0)-1][assignResult[i]-1];
                    deviceIndex = assignResult[i]-1;
                }
                else{
                    deviceTime = workResult.get(assignResult[i]-1).get(workResult.get(assignResult[i]-1).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][assignResult[i]-1];
                    deviceIndex = assignResult[i]-1;
                }
            }
            if (deviceIndex != data.deviceId.length) {
                shop.workId = i + 1;
                shop.workProcess = workProcess.get(i).get(0);
                shop.deviceId = deviceIndex + 1;
                shop.endTime = deviceTime;
                endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
                shop.startTime = shop.endTime - data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];;
                startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
                workResult.get(deviceIndex).add(shop.clone());
                workProcess.get(i).remove(0);
            }
        }
        //分配其余工序
        while (true) {
            //遍历工件
            for (int i = 0; i < data.workId.length; i++) {
                //选取工序i的剩余第一个工序
                if (workProcess.get(i).size() != 0) {
                    //System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
                    //随机生成设备遍历顺序
                    int[] orderArr = new int[data.deviceId.length];
                    for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
                    shuffle(orderArr);
                    //找到开始时间最短的机器设备
                    int deviceIndex = data.deviceId.length;
                    double deviceTime = Double.MAX_VALUE;
                    //随机遍历机器
                    for (int j = 0; j < data.deviceId.length; j++) {
                        //工序只能在可加工设备上进行加工
                        if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
                            if (workResult.get(orderArr[j]).size() == 0) {
                                //下一工序的开始时间大于等于上一工序的结束时间
                                if (workProcess.get(i).get(0) == 1) {
                                    //第一个工序
                                    deviceTime = data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                    deviceIndex = orderArr[j];
                                    break;
                                }
                            } else {
                                if (workProcess.get(i).get(0) == 1) {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]] < deviceTime) {
                                        deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                        deviceIndex = orderArr[j];
                                    }
                                } else {
                                    if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]]< deviceTime) {
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                            deviceIndex = orderArr[j];
                                        }
                                        if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
                                            deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
                                            deviceIndex = orderArr[j];
                                        }
                                    }
                                }
                            }
                        }
                        //System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
                    }
                    //更新工件信息
                    if (deviceIndex != data.deviceId.length) {
                        shop.workId = i + 1;
                        shop.workProcess = workProcess.get(i).get(0);
                        shop.deviceId = deviceIndex + 1;
                        shop.endTime = deviceTime;
                        endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
                        shop.startTime = shop.endTime - data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];;
                        startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
                        //工件信息加入结果列表
                        workResult.get(deviceIndex).add(shop.clone());
                        //删除该工序
                        workProcess.get(i).remove(0);
                    }
                }
            }
            //所有工序分配完毕时,结束
            boolean stopCondition = true;
            for (int i = 0; i < data.workId.length; i++) {
                if (workProcess.get(i).size() != 0) {
                    stopCondition = false;
                    break;
                }
            }
            if (stopCondition) break;
        }
        printResult(workResult,endTime);
    }

无论是最早开始时间还是最早结束时间策略,启发策略均能够得到可行的解方案。但是至于解方案的质量高低,还需要设计更好的启发策略。此次笔记仅实现了简单的两个启发策略,未来还有待进一步改善方法技术。

========================================
今天到此为止,后续记录其他应用问题的学习过程。
以上学习笔记,如有侵犯,请立即联系并删除!

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
柔性作业车间调度问题是一个经典的优化问题,它的目标是在一个车间中安排作业的执行顺序,以最小化总的完成时间或者最大化车间的利润。 解决这个问题可以采用各种求解方法,例如贪心算法、遗传算法、模拟退火算法、粒子群算法等等。下面简要介绍一些常用的解法: 1. 贪心算法 贪心算法是一种简单而常用的算法,它通过每一步的局部最优选择来达到全局最优。在柔性作业车间调度问题中,可以先按照作业加工时间排序,然后依次将作业分配到可用的机器上,直到所有作业都完成为止。 2. 遗传算法 遗传算法是一种模拟自然选择和遗传机制的优化算法,可以用于解决复杂的优化问题。在柔性作业车间调度问题中,可以将作业看作基因,用遗传算法作业的执行顺序进行优化。具体方法是通过交叉、变异等操作产生新的个体,并根据适应度函数选择优秀的个体进行进化。 3. 模拟退火算法 模拟退火算法是一种基于概率的全局优化算法,它通过模拟物质退火过程来寻找全局最优解。在柔性作业车间调度问题中,可以将作业执行顺序看作状态,用模拟退火算法对状态进行搜索,直到找到最优的状态。 4. 粒子群算法 粒子群算法是一种基于群体智能的优化算法,它通过模拟鸟群或鱼群的行为来优化问题。在柔性作业车间调度问题中,可以将作业执行顺序看作粒子的位置,用粒子群算法对粒子的位置进行优化,直到找到最优的位置。 以上是一些常用的求解柔性作业车间调度问题方法,实际应用时需要根据具体情况选择合适的算法,并进行参数优化和结果验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南音小榭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值