我已经使用or-tools几个月了,但是最近遇到了以下问题:
模型
s0, s1
和一个结束位置t0, t1
。x0, x1
。时间窗口:
[[5400, 5820], [9000, 9420], [5520, 39719], [6420, 43319], [5521, 39720], [6421, 43320]]
持续时间矩阵:
[
x0: [0, horizon, horizon, horizon, 5400, 5400],
x1: [horizon, 0, horizon, horizon, 1800, 1800],
s0: [0, 0, horizon, horizon, 0, horizon],
s1: [0, 0, horizon, horizon, horizon, 0],
t0: [horizon, horizon, horizon, horizon, horizon, horizon],
t1: [horizon, horizon, horizon, horizon, horizon, horizon]
]
在horizon = 86760
处-这只是消除此潜在任务的一个大值。
当我将None
传递给求解器时,会得到它。不确定为什么求解器不会返回对于s_i -> x_i -> t_i
i=0, 1
的平凡可行解
备注:
我正在使用PARALLEL_CHEAPEST_INSERTION
,因为它为我的目的提供了比PATH_CHEAPEST_ARC
更好的解决方案,但阶梯返回了正确的解决方案。
经过更多的调整后,问题似乎不在开始位置的关闭时间范围内,而在结束位置的持续时间内。也就是说,如果前两行是:
[
x0: [0, horizon, horizon, horizon, a, a],
x1: [horizon, 0, horizon, horizon, b, b],
...
对于任何 b >= a
,求解器将找到正确的分配。
index = manager.NodeToIndex(0)
routing.VehicleVar(index).SetValues([0])
index = manager.NodeToIndex(1)
routing.VehicleVar(index).SetValues([1])
我得到了正确的分配(这意味着原始模型确实可行)。
谢谢!
代码示例:
from ortools.constraint_solver import pywrapcp, routing_enums_pb2
def add_durations(manager, routing, data):
def duration_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data["durations_matrix"][from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(duration_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
routing.AddDimension(
transit_callback_index,
data["horizon"], # allow waiting time
data["horizon"], # maximum time per vehicle
False, # Don't force start cumul to zero.
"Duration"
)
duration_dimension = routing.GetDimensionOrDie('Duration')
# Add time window constraints for each location except start/end locations
for location_idx in range(data["num_locations"]):
index = manager.NodeToIndex(location_idx)
duration_dimension.CumulVar(index).SetRange(data["time_windows"][location_idx][0], data["time_windows"][location_idx][1])
routing.AddToAssignment(duration_dimension.SlackVar(index))
# Add time window constraints for each vehicle start and end locations
for vehicle_id in range(data["num_vehicles"]):
st_index = routing.Start(vehicle_id)
end_index = routing.End(vehicle_id)
duration_dimension.CumulVar(st_index).SetRange(data["time_windows"][data["num_locations"] + vehicle_id][0],
data["time_windows"][data["num_locations"] + vehicle_id][1])
duration_dimension.CumulVar(end_index).SetRange(data["time_windows"][data["num_locations"] + data["num_vehicles"] + vehicle_id][0],
data["time_windows"][data["num_locations"] + data["num_vehicles"] + vehicle_id][1])
def print_solution(data, manager, routing, assignment):
"""Prints assignment on console."""
time_dimension = routing.GetDimensionOrDie('Duration')
total_time = 0
for vehicle_id in range(data['num_vehicles']):
index = routing.Start(vehicle_id)
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
while not routing.IsEnd(index):
time_var = time_dimension.CumulVar(index)
plan_output += '{0} Time({1},{2}) -> '.format(
manager.IndexToNode(index), assignment.Min(time_var),
assignment.Max(time_var))
index = assignment.Value(routing.NextVar(index))
time_var = time_dimension.CumulVar(index)
plan_output += '{0} Time({1},{2})\n'.format(manager.IndexToNode(index),
assignment.Min(time_var),
assignment.Max(time_var))
plan_output += 'Time of the route: {}min\n'.format(
assignment.Min(time_var))
print(plan_output)
total_time += assignment.Min(time_var)
print('Total time of all routes: {}min'.format(total_time))
def run_vrp(a, b):
"""Solve the VRP with time windows."""
data = {}
data["num_vehicles"] = 2
data["num_locations"] = 2
data["time_windows"] = [[5400, 5820], [9000, 9420], [5520, 39719], [6420, 43319], [5521, 39720], [6421, 43320]]
horizon = 86760
data["horizon"] = horizon
data["durations_matrix"] = [
[0, horizon, horizon, horizon, a, a],
[horizon, 0, horizon, horizon, b, b],
[0, 0, horizon, horizon, 0, horizon],
[0, 0, horizon, horizon, horizon, 0],
[horizon, horizon, horizon, horizon, horizon, horizon],
[horizon, horizon, horizon, horizon, horizon, horizon]
]
num_all_locations = len(data["durations_matrix"])
start_locations_indices = [2, 3]
end_locations_indices = [4, 5]
manager = pywrapcp.RoutingIndexManager(
data["num_locations"] + 2 * data["num_vehicles"], data["num_vehicles"], start_locations_indices, end_locations_indices
)
routing = pywrapcp.RoutingModel(manager)
add_durations(manager, routing, data)
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION
assignment = routing.SolveWithParameters(search_parameters)
if assignment:
print_solution(data, manager, routing, assignment)
else:
print("Assignment is None")
return assignment
if __name__ == '__main__':
# doesn't work
a = 5000
b = 4000
assert run_vrp(a, b) is None
# works, because b > a
a = 3000
assert run_vrp(a, b)