习题3: 优化过程

第三次作业题涉及到一个新的优化算法: Two Edge Exchange,也叫2-opt算法。

1 Two Edge Exchange Move理论基础

2-opt算法是一个非常著名的路线规划的优化方法。其核心是,每次去除两条不相邻的路径,并将产生的子序列重新连接起来。过程如图所示:

2-opt图解

这个概念也可以应用于工业生产中的订单排期。在这里,在一个订单序列中,订单不仅作为单独的元素被考虑,订单之间的连接(路径或边)也被考虑。如果订单i直接跟随订单j,这两个订单通过一个链接,或 "边",(i,j)连接。因此,所谓的TwoEdge Exchange Move可以定义如下:

一个TwoEdgeExchange MoveM(\text{2-EdgeExchange}, s, i, j)描述了两对订单(i,i+1)(j,j+1)的连接交换。在这里,连接可能不相邻。连接(i,i+1)(j,j+1)被移除,并且被重新连接的路径或者边为:(i,j)(i+1,j+1)

a) 第一次交换

给出以下的生产序列 s=[0,1,2,3,4,5,6]。手动执行以下TwoEdgeExchange-Move:
M(\text{2-EdgeExchange}, s, 1, 4)

  • 答案:M(\text{2-EdgeExchange}, s, 1, 4) = [0, 1, 4, 3, 2, 5, 6]

*提示:思路很简单,把原本连着的 i 和 i+1 以及 j 和 j+1 断开,再把 i 和 j 连起来, i+1 和 j+1 也要连起来

b) 计算复杂度

确定TwoEdge Exchange-Move邻域的复杂性。假设一个解决方案由长度为n的置换表示,并且|j-i|geq 3成立。

注:复杂性是n的函数。

  • 答案:|N(\text{2-EdgeExchange}, s)| = 1/2 * (n-4) * (n-3)

3 TwoEdgeExchange-Move 代码实现

用TwoEdge Exchange-Move邻域来扩展前八章中创建的求解器Solver 。创建 "TwoEdgeExchangeMove"和 "TwoEdgeExchangeNeighborhood"类。

在数据集InputFlowshopSIST20.json上测试邻域。使用BestImprovement策略和FCFS初始方案。

# 2 classes in Neighborhood.py
class TwoEdgeExchangeMove:
# 这个类借鉴了前面内容中,列表元素交换的思路。我们首先定义TwoEdgeExchangeMove类,定义类的时候要注意类应具有普遍性,也就是说类应该能够适用于交换任意两个位置的订单。
# 看构造函数的参数表,我们首先需要一个初始排列,还有我们想要交换位置的元素的索引。然后在构造函数中完成交换过程,并把交换位置后的列表赋给self.Permutation,即这个类的对象的属性。
# 这样,每当我们构造一个TwoEdgeExchangeMove的对象(在循环中),这个对象的Permutation属性就被确定了
    def __init__(self, initialPermutation, indexA, indexB):
        self.Permutation = list(initialPermutation)
        self.IndexA = indexA
        self.IndexB = indexB

        # 这里需要注意细节,python中的列表包含左边,不包含右边
        # 另外还要理解2-opt的交换过程,简单说就是从序列中选两个点,A和B,A左边和B右边的节点和路径保持不变,AB中间的节点颠倒顺序
        list_left = initialPermutation[0: indexA+1]
        list_mid = reversed(initialPermutation[indexA+1: indexB+1])
        list_right = initialPermutation[indexB+1: ]

        self.Permutation = list_left+list(list_mid)+list_right

class TwoEdgeExchangeNeighborhood(BaseNeighborhood):
    def __init__(self, inputData, initialPermutation, evaluationLogic, solutionPool):
        super().__init__(inputData, initialPermutation, evaluationLogic, solutionPool)
        self.Type = 'TwoEdgeExchange'

    def DiscoverMoves(self):
        for i in range(0, len(self.Permutation)-4):
            for j in range(i+3, len(self.Permutation)-1):
                
                twoEdgeExchangeMove = TwoEdgeExchangeMove(self.Permutation, i, j)

                self.Moves.append(twoEdgeExchangeMove)

# ImprovementAlgorithm.py
def CreateNeighborhood(self, neighborhoodType, bestCurrentSolution):
    if neighborhoodType == 'Swap':
        return SwapNeighborhood(self.InputData, bestCurrentSolution.Permutation, self.EvaluationLogic, self.SolutionPool)
    elif neighborhoodType == 'Insertion':
        return InsertionNeighborhood(self.InputData, bestCurrentSolution.Permutation, self.EvaluationLogic, self.SolutionPool)
    elif neighborhoodType == 'TwoEdgeExchange':
        return TwoEdgeExchangeNeighborhood(self.InputData, bestCurrentSolution.Permutation, self.EvaluationLogic, self.SolutionPool)
    else:
        raise Exception(f"Neighborhood type {neighborhoodType} not defined.")
from Solver import *


data = InputData("InputFlowshopSIST20.json")

localSearch = IterativeImprovement(data, 'BestImprovement', ['TwoEdgeExchange'])

solver = Solver(data, 1008)

solver.RunLocalSearch(
    constructiveSolutionMethod='FCFS',
    algorithm=localSearch)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容