Created
April 10, 2019 14:42
-
-
Save daoducminh/1dfa78d2885cadefa267c63c1de8c8a3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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['distance_matrix'] = [ | |
[ | |
0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, | |
468, 776, 662 | |
], | |
[ | |
548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, | |
1016, 868, 1210 | |
], | |
[ | |
776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, | |
1130, 788, 1552, 754 | |
], | |
[ | |
696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, | |
1164, 560, 1358 | |
], | |
[ | |
582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, | |
1050, 674, 1244 | |
], | |
[ | |
274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, | |
514, 1050, 708 | |
], | |
[ | |
502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, | |
514, 1278, 480 | |
], | |
[ | |
194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, | |
662, 742, 856 | |
], | |
[ | |
308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, | |
320, 1084, 514 | |
], | |
[ | |
194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, | |
274, 810, 468 | |
], | |
[ | |
536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, | |
730, 388, 1152, 354 | |
], | |
[ | |
502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, | |
308, 650, 274, 844 | |
], | |
[ | |
388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, | |
536, 388, 730 | |
], | |
[ | |
354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, | |
342, 422, 536 | |
], | |
[ | |
468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, | |
342, 0, 764, 194 | |
], | |
[ | |
776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, | |
388, 422, 764, 0, 798 | |
], | |
[ | |
662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, | |
536, 194, 798, 0 | |
], | |
] | |
data['demands'] = [0, 1, 1, 2, 4, 2, 4, 8, 8, 1, 2, 1, 2, 4, 4, 8, 8] | |
data['pickups_deliveries'] = [ | |
[1, 6], | |
[2, 10], | |
[4, 3], | |
[5, 9], | |
[7, 8], | |
[15, 11], | |
[13, 12], | |
[16, 14], | |
] | |
data['vehicle_capacities'] = [15, 15, 15, 15] | |
data['num_vehicles'] = 4 | |
data['depot'] = 0 | |
return data | |
def print_solution(data, manager, routing, assignment): | |
"""Prints assignment on console.""" | |
total_distance = 0 | |
for vehicle_id in range(data['num_vehicles']): | |
index = routing.Start(vehicle_id) | |
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id) | |
route_distance = 0 | |
while not routing.IsEnd(index): | |
plan_output += ' {} -> '.format(manager.IndexToNode(index)) | |
previous_index = index | |
index = assignment.Value(routing.NextVar(index)) | |
route_distance += routing.GetArcCostForVehicle( | |
previous_index, index, vehicle_id) | |
plan_output += '{}\n'.format(manager.IndexToNode(index)) | |
plan_output += 'Distance of the route: {}m\n'.format(route_distance) | |
print(plan_output) | |
total_distance += route_distance | |
print('Total Distance of all routes: {}m'.format(total_distance)) | |
def main(): | |
# Instantiate the data problem. | |
data = create_data_model() | |
# Create the routing index manager. | |
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['depot']) | |
# Create Routing Model. | |
routing = pywrapcp.RoutingModel(manager) | |
# Create and register a transit callback. | |
def distance_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['distance_matrix'][from_node][to_node] | |
transit_callback_index = routing.RegisterTransitCallback(distance_callback) | |
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index) | |
# Add Distance constraint. | |
dimension_name = 'Distance' | |
routing.AddDimension( | |
transit_callback_index, | |
0, # no slack | |
3000, # vehicle maximum travel distance | |
True, # start cumul to zero | |
dimension_name) | |
distance_dimension = routing.GetDimensionOrDie(dimension_name) | |
distance_dimension.SetGlobalSpanCostCoefficient(100) | |
# Add Capacity constraint. | |
def demand_callback(from_index): | |
"""Returns the demand of the node.""" | |
# Convert from routing variable Index to demands NodeIndex. | |
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') | |
# Define Transportation Requests. | |
for request in data['pickups_deliveries']: | |
pickup_index = manager.NodeToIndex(request[0]) | |
delivery_index = manager.NodeToIndex(request[1]) | |
routing.AddPickupAndDelivery(pickup_index, delivery_index) | |
routing.solver().Add(routing.VehicleVar(pickup_index) == routing.VehicleVar(delivery_index)) | |
routing.solver().Add(distance_dimension.CumulVar(pickup_index) <= distance_dimension.CumulVar(delivery_index)) | |
# Setting first solution heuristic. | |
search_parameters = pywrapcp.DefaultRoutingSearchParameters() | |
search_parameters.first_solution_strategy = (routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) | |
search_parameters.solution_limit = 1 | |
# search_parameters.time_limit.seconds = 300 | |
# Solve the problem. | |
assignment = routing.SolveWithParameters(search_parameters) | |
# Print solution on console. | |
if assignment: | |
print_solution(data, manager, routing, assignment) | |
if __name__ == '__main__': | |
main() |
Hi.
In my case, the problem was my constraints that made it impossible to find a solution by using strategies. Therefore, it had to check every possible solutions. After changing my constraints, the model run well, and returned answer in 1 second.
This may not be the answer you need, but you can try these ways:
- Increase max capacity, number of vehicles.
- Visualize your destination locations, and find a possible solution for your dataset. Then rewrite your pickup and delivery constraint.
Hope this will help you.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey,
I am working on a similar problem statement and I tried running your code but it kept running for more than 4 hours without giving any response. After that, I had to keyboard interrupt and end the process. Do you know why its not giving the output?