Reputation: 83
I am trying to write a trip planner for which I am using Google's ORtools. The problem that I am trying to solve is that each vehicle has a different start and end depot and all the services have a different start and end time. Even the depots have a different start and end time, which need to be added as a constraint. I have been following there two examples from google's documentation:
I have scoured through all of documentations that are available for ortools, but have not been able to find a reason as to why this error is occurring. According to the documentation, what I am trying to do is possible and the code that I have written should give a correct result.
Here is a sample code of what I am doing:
"""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()
Every time I run the code for more than 2 vehicles this is the error that I am getting:
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
For 1 or 2 vehicles I am getting None
as the solution. This may be due to infeasibility of a trip for 2 vehicles.
Upvotes: 1
Views: 2256
Reputation: 11064
For each vehicle create one dummy node for the start, and one for the end, then restrict the vehicle var of these nodes to the vehicle. make these nodes optional.
Now tweak the distance matrix such that there are no arcs between the depot and any nodes. There are only arcs from the depot to the dummy start nodes, and from the dummy end nodes to the depot.
Now, it should be easy to add time constraints on these dummy nodes.
Upvotes: 2