簡體   English   中英

如何解釋從 Google OR Tools 返回的 Vehicle Routing Problem 解決方案?

[英]How do I interpret the Vehicle Routing Problem solution returned from Google OR Tools?

我有一個使用 Google 的 OR 工具 python 庫實現的有效車輛路由問題解決方案。 我有一個包含 9 個位置的時間矩陣,每個位置的時間為 windows。 所有值都以為單位。

(例如,第一次 window 是從 28800 到 28800。28800 秒相當於上午 8:00。我希望在上午 8:00 准確地訪問這個位置,倉庫

我有意只用一輛車來解決這個問題(主要是解決旅行銷售員問題)。 相信我已經正確添加了我的尺寸,但我肯定會犯錯 - 我的目的是讓車輛在任何位置等待只要它願意,只要它允許它解決車輛路線問題。 我將上限最大值設置為 86400,因為一天有 86400 秒,我認為考慮到這些數據,這將是一個足夠高的數字。

資源

from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import routing_enums_pb2

Matrix = [
  [0,557,763,1156,813,618,822,700,112],       # Depot
  [523,0,598,1107,934,607,658,535,589],       # 1 - Location
  [631,480,0,968,960,570,451,135,582],        # 2 - Location
  [1343,1247,1367,0,1270,1289,809,1193,1253], # 3 - Location
  [746,1000,1135,1283,0,1003,1186,1071,776],  # 4 - Location
  [685,627,810,1227,990,0,712,709,550],       # 5 - Location
  [869,718,558,732,1105,650,0,384,821],       # 6 - Location
  [679,528,202,878,1008,618,412,0,630],       # 7 - Location
  [149,626,762,1124,696,532,821,698,0]        # 8 - Location
]

Windows = [
  [ 28800, 28800 ], # Depot
  [ 43200, 43200 ], # 1 - Location
  [ 50400, 50400 ], # 2 - Location
  [ 21600, 79200 ], # 3 - Location
  [ 21600, 79200 ], # 4 - Location
  [ 21600, 79200 ], # 5 - Location
  [ 21600, 79200 ], # 6 - Location
  [ 21600, 79200 ], # 7 - Location
  [ 21600, 79200 ]  # 8 - Location
]

# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(Matrix), 1, 0)

# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)

# Create and register a transit callback.
def time_callback(from_index, to_index):
  # Returns the travel time between the two nodes.
  # Convert from routing variable Index to time matrix NodeIndex.
  from_node = manager.IndexToNode(from_index)
  to_node = manager.IndexToNode(to_index)
  return Matrix[from_node][to_node]

transit_callback_index = routing.RegisterTransitCallback(time_callback)

# Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# Add Time Windows constraint.
routing.AddDimension(
    transit_callback_index,
    86400,  # An upper bound for slack (the wait times at the locations).
    86400,  # An upper bound for the total time over each vehicle's route.
    False,  # Determine whether the cumulative variable is set to zero at the start of the vehicle's route.
    'Time')
time_dimension = routing.GetDimensionOrDie('Time')

# Add time window constraints for each location except depot.
for location_idx, time_window in enumerate(Windows):
  if location_idx == 0:
    continue
  index = manager.NodeToIndex(location_idx)
  time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])

# Add time window constraints for each vehicle start node.
index = routing.Start(0)
time_dimension.CumulVar(index).SetRange(Windows[0][0],Windows[0][1])

# Instantiate route start and end times to produce feasible times.
routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.Start(0)))
routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.End(0)))

# Setting first solution heuristic. 
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

# Setting local search metaheuristics:
search_parameters.local_search_metaheuristic = (routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
search_parameters.time_limit.seconds = 5
search_parameters.log_search = False

# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)

# Return the solution.
time = 0
index = routing.Start(0)
print("Locations:")
while not routing.IsEnd(index):
  time = time_dimension.CumulVar(index)
  print("{0} ({1}, {2})".format(manager.IndexToNode(index),solution.Min(time),solution.Max(time)))
  index = solution.Value(routing.NextVar(index))
print("{0} ({1}, {2})".format(manager.IndexToNode(index),solution.Min(time),solution.Max(time)))

Output

Locations:
0 (28800, 28800)
8 (28912, 42041)
5 (29444, 42573)
1 (43200, 43200)
2 (50400, 50400)
7 (50535, 50535)
6 (50947, 50947)
3 (51679, 51679)
4 (52949, 52949)
0 (52949, 52949)

我的問題是關於解決方案為我計算的 output。 我對解決方案中第二個和第三個位置的時間 windows 感到困惑。 我一直期望 windows 看起來像結果的 rest。 當我處理我的解決方案時,這個問題的 scope 中的solution.Min()solution.Max()值是什么意思? 我在使用 OR Tools 時是否有任何明顯的錯誤?

我對這個元組的理解是你有

(Min_time, Max_time)

其中Min_time是您應該到達以滿足時間 Window 的最短時間。 對於Max_time也是完全一樣的邏輯。

當您可以到達滿足約束的節點時,程序會輸出一個范圍。

Locations:
0 (28800, 28800) // must arrive and leave no later than 28800
8 (28912, 42041) // must arrive at or after 28912 and leave no later than 42041
5 (29444, 42573) // must arrive at or after 29444and leave no later than 42573
1 (43200, 43200) // must arrive and leave no later than 43200
2 (50400, 50400) // must arrive and leave no later than 50400

請參閱我添加的評論。 當到達時間是一個范圍時,比如說節點 8 或 5,它基本上意味着到達時間需要落在那個時間范圍內。 只要滿足該條件,該解決方案仍然可行。

您可以按如下方式進行驗證:

Depot [28800, 28800] -> Travel (0, 8) 112-> Loc 8 [21600, 79200] -> Travel (8, 5) 532 -> Loc 5 [21600, 79200] -> Travel (5, 1) 685 -> Loc 1 [43200, 43200]

在時間 28800 出發,行程時間為 112,您將在時間 28912(您的解決方案中的最小值)到達地點 8(您的解決方案中的最小值),立即出發,行程時間為 532,您將在時間 29444 到達地點 5。

現在, loc 1有一個可用的時隙,即43200 因此,如果車輛在時間29444離開,行程時間為627 ,它將在時間30071到達loc 1 ,這不是有效的到達時間。 但如果車輛在43200-627= 42573出發,它將准時到達。 所以這意味着車輛需要閑置(松弛)一段時間才能go。 由於loc 8loc 5都有一個范圍,解決方案是說明在這些位置有一些可用的 slack。 所以最小值和最大值真正告訴你的是,只要到達和離開在這些范圍內,解決方案是可行的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM