我正在尝试编写一个旅行计划器,并且正在使用Google的ORtools。我要解决的问题是,每辆车都有不同的起点和终点站,所有服务的起点和终点时间都不同。甚至仓库都有不同的开始时间和结束时间,需要添加这些时间作为约束。我一直在关注Google文档中的两个示例:
我已经仔细阅读了所有可用于ortools的文档,但是无法找到发生此错误的原因。根据文档,我正在尝试做的事情是可能的,并且我编写的代码应该给出正确的结果。
这是我正在做的示例代码:
"""Simple Vehicles Routing Problem."""
from __future__ import print_function
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
def create_data_model():
"""Stores the data for the problem."""
data = {}
data['time_matrix'] = [
[0, 6, 7, 9, 7, 3, 6, 2, 3, 2, 6, 6, 4, 4, 5, 9, 7, 0],
[6, 0, 8, 3, 2, 6, 8, 4, 8, 8, 13, 7, 5, 8, 12, 12, 14, 6],
[7, 8, 0, 11, 10, 6, 3, 9, 5, 8, 4, 15, 14, 13, 9, 18, 9, 15],
[9, 3, 11, 0, 3, 7, 10, 6, 10, 10, 14, 6, 7, 9, 14, 6, 16, 14],
[7, 2, 10, 3, 0, 6, 9, 4, 8, 9, 13, 4, 6, 8, 12, 8, 14, 9],
[3, 6, 6, 7, 6, 0, 2, 8, 2, 2, 7, 9, 7, 7, 6, 12, 8, 3],
[6, 8, 3, 10, 9, 2, 0, 6, 2, 5, 4, 12, 10, 10, 6, 11, 5, 10],
[2, 4, 9, 6, 4, 8, 6, 0, 4, 4, 8, 5, 4, 13, 7, 8, 10, 12],
[3, 8, 5, 10, 8, 2, 2, 4, 0, 3, 4, 9, 8, 7, 3, 13, 6, 5],
[2, 8, 8, 10, 9, 2, 5, 4, 3, 0, 4, 6, 5, 4, 3, 9, 5, 8],
[6, 13, 4, 14, 13, 7, 4, 8, 4, 4, 0, 10, 9, 8, 4, 13, 4, 9],
[6, 7, 15, 6, 4, 9, 12, 5, 9, 6, 10, 0, 1, 3, 7, 13, 10, 11],
[4, 5, 14, 7, 6, 7, 10, 4, 8, 5, 9, 1, 0, 2, 16, 4, 8, 1],
[4, 8, 13, 9, 8, 7, 10, 13, 7, 4, 8, 3, 2, 0, 4, 5, 6, 2],
[5, 12, 9, 14, 12, 6, 6, 7, 3, 3, 4, 7, 16, 4, 0, 9, 12, 4],
[9, 12, 18, 6, 8, 12, 11, 8, 13, 9, 13, 13, 4, 5, 9, 0, 9, 10],
[7, 14, 9, 16, 14, 8, 5, 10, 6, 5, 4, 10, 8, 6, 12, 9, 0, 13],
[0, 6, 15, 14, 9, 3, 10, 12, 5, 8, 9, 11, 1, 2, 4, 10, 13, 0]
]
data['time_windows'] = [
(0, 22), # depot
(7, 12), # 1
(10, 15), # 2
(6, 8), # 3
(10, 13), # 4
(0, 5), # 5
(5, 10), # 6
(0, 4), # 7
(5, 7), # 8
(0, 3), # 9
(10, 16), # 10
(10, 15), # 11
(0, 9), # 12
(5, 10), # 13
(7, 10), # 14
(10, 15), # 15
(11, 15), # 16
(18, 25) # 17
]
data['num_days'] = 3
data['start'] = [0,0,0]#, 0, 0, 0] # ,17,0,17]
data['end'] = [17,17,17]#, 17, 17, 17]
return data
def print_solution(data, manager, routing, assignment):
# prints the final routing solution on the console
time_dimension = routing.GetDimensionOrDie('Time')
total_time = 0
for vehicle_id in range(data['num_days']):
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 main():
"""Entry point of the program."""
# Instantiate the data problem.
data = create_data_model()
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']), data['num_days'], data['start'], data['end'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
# Create and register a transit callback.
def time_callback(from_index, to_index):
"""Returns the distance between the two nodes."""
# Convert from routing variable Index to distance matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data['time_matrix'][from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(time_callback)
# Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# Add time constraint.
dimension_name = 'time'
routing.AddDimension(
transit_callback_index,
30, # no slack
1000000000, # vehicle maximum travel distance
False, # start cumul to zero
dimension_name)
time_dimension = routing.GetDimensionOrDie(dimension_name)
# add time window constraints
for location_idx, time_window in enumerate(data['time_windows']):
if location_idx == 17 or 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.
for vehicle_id in range(data['num_days']):
index = routing.Start(vehicle_id)
end_index = routing.End(vehicle_id)
print(end_index)
time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],
data['time_windows'][0][1])
time_dimension.CumulVar(end_index).SetRange(data['time_windows'][17][0],
data['time_windows'][17][1])
for i in range(data['num_days']):
routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.Start(i)))
routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.End(i)))
time_dimension.SetSpanCostCoefficientForAllVehicles(200)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
print(solution)
# Print solution on console.
if solution:
print_solution(data, manager, routing, solution)
if __name__ == '__main__':
main()
每次我为两辆以上的车辆运行代码时,这就是我得到的错误:
RuntimeError: SWIG std::function invocation failed.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/travelapp/PycharmProjects/TravelApp/venv/lib/python3.7/site-packages/ortools/constraint_solver/pywrapcp.py", line 2136, in <lambda>
__setattr__ = lambda self, name, value: _swig_setattr(self, Assignment, name, value)
File "/Users/travelapp/PycharmProjects/TravelApp/venv/lib/python3.7/site-packages/ortools/constraint_solver/pywrapcp.py", line 71, in _swig_setattr
return _swig_setattr_nondynamic(self, class_type, name, value, 0)
File "/Users/travelapp/PycharmProjects/TravelApp/venv/lib/python3.7/site-packages/ortools/constraint_solver/pywrapcp.py", line 55, in _swig_setattr_nondynamic
if type(value).__name__ == 'SwigPyObject':
SystemError: <class 'type'> returned a result with an error set
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/travelapp/Library/Preferences/PyCharmCE2019.1/scratches/scratch.py", line 150, in <module>
main()
File "/Users/travelapp/Library/Preferences/PyCharmCE2019.1/scratches/scratch.py", line 142, in main
solution = routing.SolveWithParameters(search_parameters)
File "/Users/travelapp/PycharmProjects/TravelApp/venv/lib/python3.7/site-packages/ortools/constraint_solver/pywrapcp.py", line 3464, in SolveWithParameters
return _pywrapcp.RoutingModel_SolveWithParameters(self, search_parameters, solutions)
SystemError: <built-in function RoutingModel_SolveWithParameters> returned a result with an error set
对于1或2辆车,我得到None
作为解决方案。这可能是由于2辆车旅行不可行。
答案 0 :(得分:1)
为每辆车创建一个虚拟节点作为起点,并为终点创建一个哑节点,然后将这些节点的车辆变量限制为该车辆。将这些节点设为可选。
现在调整距离矩阵,以便在仓库和任何节点之间没有弧线。 从仓库到虚拟起始节点,从虚拟结束节点到仓库只有弧。
现在,在这些虚拟节点上添加时间限制应该很容易。