import numpy as np
import ortools
from ortools.constraint_solver import pywrapcp, routing_enums_pb2
import matplotlib.pyplot as plt
def extract_solution(transformed_data, manager, routing, solution, time_dimension):
solution_list = [[] for _ in range(transformed_data['num_vehicles'])] # Storage for solution.
time_list = [[] for _ in range(transformed_data['num_vehicles'])] # Storage for time.
for vehicle in range(transformed_data['num_vehicles']): # Iterating over all the vehicles.
index = routing.Start(vehicle) # Starting index of a specific vehicle.
while not routing.IsEnd(index): # Running the loop till the index is not last.
solution_list[vehicle].append(manager.IndexToNode(index)) # Appending the node of a specific vehicle.
time_var = time_dimension.CumulVar(index)
time_list[vehicle].append((solution.Min(time_var), # Appending the time required.
solution.Max(time_var)))
index = solution.Value(routing.NextVar(index)) # Assigning the next index.
# Including the last node values.
solution_list[vehicle].append(manager.IndexToNode(index))
time_var = time_dimension.CumulVar(index)
time_list[vehicle].append((solution.Min(time_var), solution.Max(time_var)))
return solution_list, time_list
def create_data_model():
data = {}
data['coordinates'] = {0: (5, 5),
1: (5, 10),
2: (10, 10),
3: (10, 5),
4: (5, 0),
5: (0, 0),
6: (0, 5)}
data['time_matrix'] = [[int(abs(np.linalg.norm(np.array(v) - np.array(v_)))) for k, v_ in data['coordinates'].items()] for k, v in data['coordinates'].items()]
data['num_vehicles'] = 2
data['demands'] = [0, 4, 4, 2, 4, 2, 4, 8]
data['vehicle_capacities'] = [15 for _ in range(data['num_vehicles'])]
data['depot'] = 0
return data
def main():
data = create_data_model()
manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),
data['num_vehicles'], data['depot'])
routing = pywrapcp.RoutingModel(manager)
# Time callback
def time_callback(from_index, to_index):
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)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
time = 'Time'
routing.AddDimension(
transit_callback_index,
300, # allow waiting time
300, # maximum time per vehicle
False, # Don't force start cumul to zero.
time)
time_dimension = routing.GetDimensionOrDie(time)
time_dimension.SetGlobalSpanCostCoefficient(100)
# Add Capacity constraint.
def demand_callback(from_index):
from_node = manager.IndexToNode(from_index)
return data['demands'][from_node]
demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities'], # vehicle maximum capacities
True, # start cumul to zero
'Capacity')
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
search_parameters.local_search_metaheuristic = (routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
search_parameters.time_limit.seconds = 10
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
solution_list, time_list = extract_solution(data, manager,
routing, solution, time_dimension)
total_time = sum([t[-1][1] for t in time_list if len(t) > 0])
# Printing
print('Solution')
print(solution_list)
print('Time')
print(time_list)
print('Total time', total_time)
# Plotter.
x, y = list(zip(*list(data['coordinates'].values())[1:]))
plt.scatter(data['coordinates'][0][0], data['coordinates'][0][1],
marker = 's', s = 40, color = 'k')
plt.scatter(x, y,
marker = 'o', s = 40, color = 'r')
for sol in solution_list:
if len(sol) > 2:
xs, ys = list(zip(*[data['coordinates'].get(k) for k in sol]))
plt.plot(xs, ys)
plt.show()
if __name__ == '__main__':
main()