80、ALNS实现

from VRP.CVRP.tool.Value import *
from VRP.CVRP.method.Init.Insert import *
from VRP.CVRP.tool.Graph_transform import *

class Input:
    def __init__(self, points, capacity, XBest, valueBest):
        self.points = points
        self.capacity = capacity
        self.XBest = XBest
        self.valueBest = valueBest
        self.X = XBest
        self.value = valueBest
        self.XTest = None
        self.scatters = None
        self.functionRecord = {}

    def __repr__(self):
        return str([self.points, self.capacity,
                    self.XBest, self.valueBest,
                    self.X, self.value,
                    self.XTest, self.scatters])

def AXPlot(A, X, points):
    # 价值
    value = fX(X, points)
    print("value: ", value)

    #分点图
    LS = Directed_to_sequence(A)
    clusters_sequence_plot(points, LS)

    #路线图
    # A_plot(points, A, x_min, y_min, x_max, y_max)

# random removal removes requests uniformal at random.
# Random Removal might seem to be an unfavorable destory strategy at first glance because it could remove the already
# fitting parts of a solution. Still, it has a very positive effect because it provides diversification. As the sole
# destory heuristic it may not be productive enough.
# 随机去掉一些点
def randomRemoval(input):
    if rd.random() < 0.5:
        X = input.X
    else:
        X = input.XBest
    points = input.points
    # 一半概率全局采样,一半概率每个区域拿一个出来
    if rd.random() < 0.5:
        scatters = rd.sample(range(1,len(points)), len(X))
    else:
        scatters = []
        for route in X:
            scatters.append(rd.choice(route[1:]))

    XTest = [[p for p in route if p not in scatters] for route in X]
    input.XTest = XTest
    input.scatters = scatters

#算边际距离
def ds(point, pointBefore, pointNext):
    s1 = calculate_distance(point.x, point.y, pointBefore.x, pointBefore.y) + \
         calculate_distance(point.x, point.y, pointNext.x, pointNext.y)
    s2 = calculate_distance(pointBefore.x, pointBefore.y, pointNext.x, pointNext.y)
    return s1-s2

# The idea of worst removal is to remove is to remove the worst parts of the solution, i.e. those that cause the biggest
# costs, hoping that the repair heuristic is able to eliminate the huge costs. The common way to determine the individual
# costs of certain parts of a solution is to calculate the difference of the costs of the solution and the costs of the
# solution without that part
# 把一些边际成本高的去掉
def worstRemoval(input):
    if rd.random() < 0.5:
        X = input.X
    else:
        X = input.XBest
    points = input.points
    scatters = []
    #每个路线中拿一个边际距离最长的出来
    for route in X:
        Lds = []
        for i in range(1, len(route)-1):
            point, pointBefore, pointNext = points[route[i]], points[route[i-1]], points[route[i+1]]
            Lds.append([route[i], ds(point, pointBefore, pointNext)])
        point, pointBefore, pointNext = points[route[-1]], points[route[-2]], points[route[0]]
        Lds.append([route[len(route)-1], ds(point, pointBefore, pointNext)])
        Lds.sort(key=lambda x:x[1], reverse=True)
        scatters.append(Lds[0][0])
    XTest = [[p for p in route if p not in scatters] for route in X]
    input.XTest = XTest
    input.scatters = scatters

#思想是要聚类
#这里做法是每个点找到其最近的点,然后随机去掉点对
def relatedRemoval(input):
    if rd.random() < 0.5:
        X = input.X
    else:
        X = input.XBest
    points = input.points
    scatters = []
    for route in X:
        pairs = []
        #路径上除去起点外点数要超过2才行
        if len(route) >= 3:
            for i in range(1, len(route)):
                pi = points[route[i]]
                pNear = None
                disNear = None
                for j in range(1, len(route)):
                    if i == j:
                        continue
                    pj = points[route[j]]
                    dis = calculate_distance(pi.x, pi.y, pj.x, pj.y)
                    if disNear is None or disNear > dis:
                        pNear = route[j]
                        disNear = dis
                pairs.append([route[i], pNear])
            pair = rd.choice(pairs)
            scatters += pair
    XTest = [[p for p in route if p not in scatters] for route in X]
    input.XTest = XTest
    input.scatters = scatters

#基于历史信息的
def historyBasedRemoval(input):
    pass

#货量大的点先插入,按损失最小的原则贪心插入
def greedyInsertion(input):
    points = input.points
    scatters = input.scatters
    #散点根据货量倒排
    pairs = [[p, points[p].demand] for p in scatters]
    pairs.sort(key=lambda x:x[1], reverse=True)
    scatters = [pair[0] for pair in pairs]
    XTest = input.XTest
    capacity = input.capacity
    flag = True
    for idx in scatters:
        p = points[idx]
        idxi, idxj = -1, -1
        cost = -1
        for i in range(len(XTest)):
            #当货物超了则跳过
            ci = sum([points[j].demand for j in XTest[i]])
            if ci+p.demand > capacity:
                continue
            for j in range(1, len(XTest[i])):
                before = points[XTest[i][j-1]]
                after = points[XTest[i][j]]
                costij = calculate_distance(p.x, p.y, before.x, before.y) + \
                         calculate_distance(p.x, p.y, after.x, after.y) - \
                         calculate_distance(before.x, before.y, after.x, after.y)
                if cost == -1 or cost > costij:
                    idxi = i
                    idxj = j
                    cost = costij
            before = points[XTest[i][-1]]
            after = points[XTest[i][0]]
            costij = calculate_distance(p.x, p.y, before.x, before.y) + \
                     calculate_distance(p.x, p.y, after.x, after.y) - \
                     calculate_distance(before.x, before.y, after.x, after.y)
            if cost == -1 or cost > costij:
                idxi = i
                idxj = len(XTest[i])
                cost = costij
        #如果有个点插不进去了,则终止
        if idxi == -1:
            flag = False
            break
        XTest[idxi] = XTest[idxi][:idxj] + [idx] + XTest[idxi][idxj:]
    if not flag:
        input.XTest = None
        input.scatters = None
        return
    input.X = XTest
    input.value = fX(XTest, points)
    if input.valueBest > input.value:
        input.valueBest = input.value
        input.XBest = input.X
    input.XTest = None
    input.scatters = None

#Regret heuristics do not take the minimum insertion cost into account but also the second cheapest, third cheapest and
#so on. In general, a Regret-n heuristic calculates the part with the greatest cost difference between the cheapest and
#the n-1 next cheapest insertions. the following formula expresses that by using the symbol si(p) for the i-cheapest
#solution in which part p has already been inserted
#不仅尝试局部最优的,也看第二、第三等等,关注的是
def regretHeuristics(input, nRegret=3):
    points = input.points
    scatters = input.scatters
    # 散点根据货量倒排
    pairs = [[p, points[p].demand] for p in scatters]
    pairs.sort(key=lambda x: x[1], reverse=True)
    scatters = [pair[0] for pair in pairs]
    XTest = input.XTest
    capacity = input.capacity
    flag = True
    for idx in scatters:
        p = points[idx]
        LL = []
        for i in range(len(XTest)):
            # 当货物超了则跳过
            ci = sum([points[j].demand for j in XTest[i]])
            if ci + p.demand > capacity:
                continue
            for j in range(1, len(XTest[i])):
                before = points[XTest[i][j - 1]]
                after = points[XTest[i][j]]
                costij = calculate_distance(p.x, p.y, before.x, before.y) + \
                         calculate_distance(p.x, p.y, after.x, after.y) - \
                         calculate_distance(before.x, before.y, after.x, after.y)
                LL.append([i, j, costij])
            before = points[XTest[i][-1]]
            after = points[XTest[i][0]]
            costij = calculate_distance(p.x, p.y, before.x, before.y) + \
                     calculate_distance(p.x, p.y, after.x, after.y) - \
                     calculate_distance(before.x, before.y, after.x, after.y)
            LL.append([i, len(XTest[i]), costij])
        # 如果有个点插不进去了,则终止
        if len(LL) == 0:
            flag = False
            break
        LL.sort(key=lambda x:x[2])
        pair = rd.choice(LL[:min(len(LL), nRegret)])
        idxi, idxj = pair[0], pair[1]
        XTest[idxi] = XTest[idxi][:idxj] + [idx] + XTest[idxi][idxj:]
    if not flag:
        input.XTest = None
        input.scatters = None
        return
    input.X = XTest
    input.value = fX(XTest, points)
    if input.valueBest > input.value:
        input.valueBest = input.value
        input.XBest = input.X
    input.XTest = None
    input.scatters = None

#记录方法对的调用频次及优化幅度
def functionRecordCount(destory, repair, valueOri, valueOpt, input):
    D = input.functionRecord
    if (destory.__name__, repair.__name__) not in D:
        D[destory.__name__, repair.__name__] = [0, 0]
    D[destory.__name__, repair.__name__][0] += 1
    D[destory.__name__, repair.__name__][1] += valueOri - valueOpt

def NS(X, points, capacity):
    input = Input(points, capacity, X, fX(X, points))
    destoryList = [randomRemoval, worstRemoval, relatedRemoval, historyBasedRemoval]
    destoryList = [randomRemoval, worstRemoval, relatedRemoval]
    repairsList = [greedyInsertion, regretHeuristics]
    # repairsList = [greedyInsertion]
    loop = 0
    while loop < 100:
        print(loop)
        valueOri = input.valueBest
        destory = rd.choice(destoryList)
        repair = rd.choice(repairsList)
        destory(input)
        repair(input)
        valueOpt = input.valueBest
        functionRecordCount(destory, repair, valueOri, valueOpt, input)
        # clusters_sequence_plot(points, input.XBest)
        loop += 1
    print("functionRecord: ", input.functionRecord)
    return input.XBest, input.valueBest

if __name__ == "__main__":

    #这里先定义一下标准的CVRP问题,简单的,先看同构车型
    #点的范围及个数
    x_min, y_min, x_max, y_max, nums = 0,0,100,100,10

    #车容量
    capacity = 10

    #点集生成
    points = points_generate_CVRP(x_min, y_min, x_max, y_max, nums, capacity)
    points = [[0, 50, 50, 0], [1, 37, 94, 4], [2, 5, 86, 3], [3, 95, 55, 4], [4, 38, 15, 4], [5, 75, 28, 4], [6, 23, 98, 2],[7, 1, 89, 3], [8, 24, 22, 3], [9, 54, 44, 3]]
    points = [[0, 50, 50, 0], [1, 13, 58, 4], [2, 11, 20, 4], [3, 56, 29, 4], [4, 9, 23, 2], [5, 38, 58, 3], [6, 17, 40, 2], [7, 72, 23, 4], [8, 54, 61, 4], [9, 3, 62, 4]]
    points = LL2points(points)
    print(points)

    #初始化
    A = insert(points, capacity)
    X = Directed_to_sequence(A)
    AXPlot(A, X, points)

    #迭代
    XBest, valueBest = NS(X, points, capacity)
    print("valueBest: ", valueBest)
    clusters_sequence_plot(points, XBest)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值