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)
80、ALNS实现
最新推荐文章于 2023-09-14 18:37:48 发布