Last active
July 4, 2024 14:14
-
-
Save Mizux/36a87040af87eb9c5324d49224f709ac to your computer and use it in GitHub Desktop.
Revisions
-
Mizux revised this gist
Jul 4, 2024 . 2 changed files with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes.File renamed without changes. -
Mizux created this gist
Jul 4, 2024 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,277 @@ #!/usr/bin/env python3 """Development In Progress CVRPTW. or-tools == 9.9.3963 python == 3.11.7 Number of Regular Nodes = 16, Depot Nodes = 1 Number of Nodes Duplicated = 16(Same as Number of Regular Nodes) Total Nodes = 16+16+1 = 33 Demnds = 0 for Depot, 1 for Regular Nodes and -1 for Duplicate Nodes. Time Windwos = Applied Business Logic for Regular Nodes and Whole Day for Duplicate Nodes. pickup_dropoff = Regular Node Index, len(data)+Regular Node Index """ import numpy as np from ortools.routing import enums_pb2 from ortools.routing import pywraprouting FirstSolutionStrategy = enums_pb2.FirstSolutionStrategy LocalSearchMetaheuristic = enums_pb2.LocalSearchMetaheuristic RoutingSearchStatus = enums_pb2.RoutingSearchStatus def create_data_model(): data = {} num_depots = 1 patient_len = 16 vehicle_capacity = 3 data["num_Locations"] = 2 * patient_len + num_depots # fmt:off # data['demands'] = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3] # for the Demands Tried adding Vehicle_Capacity(-3) instead of -1, Vehicle Didnt Visit Any Nodes. But adding -1 yielded result data['demands']=[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] data['time_windows']=[(0, 86400), (23400, 25200), (23400, 25200), (23400, 25200), (23400, 25200), (23400, 25200), (28800, 28800), (28800, 28800), (32400, 32400), (32400, 32400), (36000, 36000), (36000, 36000), (36000, 36000), (39600, 39600), (39600, 39600), (43200, 43200), (43200, 43200), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400), (0, 86400)] data['num_vehicles']= 40 data['vehicle_capacity'] = [vehicle_capacity for _ in range(data['num_vehicles'])] data['depot']=0 data['pickup_dropoff']=[(1, 17), (2, 18), (3, 19), (4, 20), (5, 21), (6, 22), (7, 23), (8, 24), (9, 25), (10, 26), (11, 27), (12, 28), (13, 29), (14, 30), (15, 31), (16, 32)] data['duplicate_nodes']=patient_len+1 # INdex of Start of Duplicate Node data['distance_matrix'] = [ [ 0 ,18432 , 8219 , 7741 ,21036 ,11099 ,28697 ,21912 ,31279 ,39777 ,35803 , 8667 ,71688 ,12592 ,11929 ,21985 ,18432 ], [17866 , 0 ,10701 ,16151 ,21228 ,29756 ,25445 ,22105 ,31472 ,36525 ,48423 ,10499 ,68436 ,14823 ,14225 ,12439 , 0 ], [ 8084 ,10986 , 0 , 6369 ,13032 ,19974 ,21474 ,13909 ,23623 ,32555 ,38641 , 1221 ,64465 , 4799 , 4140 ,14762 ,10986 ], [ 7268 ,16304 , 6090 , 0 ,18907 ,19158 ,26568 ,19783 ,31148 ,37649 ,32296 , 6538 ,69559 ,10463 , 9800 ,19856 ,16304 ], [19622 ,21970 ,12496 ,17908 , 0 ,31512 ,13404 , 4291 ,13905 ,26053 ,37574 ,11758 ,56084 , 8945 , 9289 ,18362 ,21970 ], [11208 ,30040 ,19827 ,19349 ,32644 , 0 ,40305 ,33520 ,42887 ,51385 ,47721 ,20275 ,83296 ,24200 ,23536 ,33593 ,30040 ], [28383 ,26104 ,21364 ,26669 ,15291 ,40273 , 0 ,13247 ,15930 ,14162 ,46324 ,20465 ,46072 ,21785 ,22129 ,15111 ,26104 ], [20790 ,23138 ,13664 ,19075 , 4208 ,32680 ,11417 , 0 ,10501 ,24831 ,37917 ,12926 ,54862 ,10113 ,10457 ,20970 ,23138 ], [31108 ,33154 ,23981 ,29142 ,14263 ,42997 ,17630 ,11016 , 0 ,24328 ,31712 ,23243 ,50310 ,19040 ,19699 ,28100 ,33154 ], [39053 ,36774 ,32034 ,37339 ,26278 ,50943 ,12623 ,24234 ,25334 , 0 ,69610 ,31135 ,32389 ,36012 ,35353 ,25781 ,36774 ], [37147 ,49357 ,39144 ,31154 ,39309 ,45936 ,47054 ,38162 ,32604 ,57812 , 0 ,39592 ,87181 ,43516 ,42853 ,52910 ,49357 ], [ 8344 ,10812 , 1179 , 6629 ,12035 ,20234 ,20257 ,12911 ,22229 ,31337 ,38901 , 0 ,63248 , 5003 , 4344 ,13545 ,10812 ], [70605 ,68325 ,63585 ,68890 ,54839 ,82495 ,43646 ,52795 ,49929 ,26387 ,80816 ,62687 , 0 ,61333 ,61677 ,57333 ,68325 ], [12370 ,14944 , 4734 ,10655 , 8988 ,24259 ,24531 , 9864 ,18076 ,35611 ,42926 , 4653 ,62123 , 0 , 658 ,17819 ,14944 ], [11711 ,14285 , 4075 , 9996 , 9332 ,23600 ,23872 ,10208 ,18734 ,34952 ,42267 , 3994 ,62467 , 658 , 0 ,17160 ,14285 ], [21792 ,12856 ,14773 ,20077 ,19004 ,33682 ,15385 ,19880 ,26223 ,26465 ,52349 ,13874 ,58376 ,18750 ,18091 , 0 ,12856 ], [17866 , 0 ,10701 ,16151 ,21228 ,29756 ,25445 ,22105 ,31472 ,36525 ,48423 ,10499 ,68436 ,14823 ,14225 ,12439 , 0 ], ] data['duration_matrix']=[ [ 0 , 1468 , 564 , 528 , 1535 , 864 , 1797 , 1630 , 2442 , 2552 , 1737 , 614 , 3806 , 916 , 870 , 1501 , 1468 ], [1391 , 0 , 939 , 1229 , 1685 , 2157 , 1949 , 1781 , 2592 , 2704 , 2610 , 921 , 3958 , 1194 , 1167 , 1167 , 0 ], [ 612 , 1026 , 0 , 450 , 1165 , 1378 , 1475 , 1260 , 2017 , 2230 , 1832 , 173 , 3485 , 445 , 388 , 1180 , 1026 ], [ 515 , 1306 , 402 , 0 , 1373 , 1282 , 1635 , 1468 , 2238 , 2390 , 1506 , 452 , 3644 , 755 , 708 , 1339 , 1306 ], [1488 , 1699 , 1077 , 1327 , 0 , 2255 , 1216 , 450 , 1297 , 1998 , 2616 , 968 , 2941 , 895 , 929 , 1470 , 1699 ], [ 801 , 2204 , 1301 , 1265 , 2272 , 0 , 2533 , 2367 , 3178 , 3288 , 2511 , 1351 , 4542 , 1653 , 1607 , 2238 , 2204 ], [1805 , 1968 , 1438 , 1644 , 1069 , 2572 , 0 , 958 , 1318 , 1113 , 2858 , 1318 , 2368 , 1572 , 1607 , 1051 , 1968 ], [1620 , 1831 , 1208 , 1458 , 445 , 2386 , 1062 , 0 , 1060 , 1879 , 2512 , 1100 , 2821 , 1026 , 1061 , 1557 , 1831 ], [2427 , 2680 , 2015 , 2189 , 1345 , 3194 , 1433 , 1097 , 0 , 2052 , 2065 , 1907 , 2937 , 1802 , 1860 , 2218 , 2680 ], [2549 , 2712 , 2182 , 2387 , 1980 , 3315 , 1130 , 1869 , 1986 , 0 , 3769 , 2062 , 1751 , 2421 , 2363 , 1794 , 2712 ], [1906 , 2784 , 1880 , 1494 , 2655 , 2516 , 3025 , 2534 , 2047 , 3862 , 0 , 1930 , 4808 , 2233 , 2186 , 2817 , 2784 ], [ 617 , 989 , 165 , 456 , 1059 , 1384 , 1308 , 1154 , 1937 , 2063 , 1837 , 0 , 3317 , 451 , 393 , 1012 , 989 ], [3862 , 4024 , 3495 , 3700 , 2895 , 4628 , 2432 , 2784 , 2858 , 1643 , 4725 , 3375 , 0 , 3397 , 3432 , 3107 , 4024 ], [ 913 , 1297 , 428 , 751 , 922 , 1679 , 1684 , 1017 , 1752 , 2439 , 2132 , 431 , 3435 , 0 , 57 , 1388 , 1297 ], [ 855 , 1240 , 371 , 693 , 957 , 1622 , 1626 , 1052 , 1810 , 2381 , 2075 , 374 , 3470 , 57 , 0 , 1331 , 1240 ], [1488 , 1267 , 1120 , 1326 , 1529 , 2254 , 1121 , 1624 , 2266 , 1876 , 2707 , 1000 , 3130 , 1360 , 1302 , 0 , 1267 ], [1391 , 0 , 939 , 1229 , 1685 , 2157 , 1949 , 1781 , 2592 , 2704 , 2610 , 921 , 3958 , 1194 , 1167 , 1167 , 0 ], ] # fmt:off assert data['num_Locations']==len(data['time_windows']) assert len(data['distance_matrix'])*2-1 == data['num_Locations'] assert len(data['duration_matrix'])*2-1 == data['num_Locations'] assert data['num_Locations']==len(data['demands']) return data def print_solution(manager, routing, solution): """Prints solution on console.""" status = routing.status() print(f"Status: {RoutingSearchStatus.Value.Name(status)}") if ( status != RoutingSearchStatus.ROUTING_OPTIMAL and status != RoutingSearchStatus.ROUTING_SUCCESS ): print("No solution found!") return print(f"Objective: {solution.ObjectiveValue()}") # Display dropped nodes. dropped_nodes = "Dropped nodes:" for node in range(routing.Size()): if routing.IsStart(node) or routing.IsEnd(node): continue if solution.Value(routing.NextVar(node)) == node: dropped_nodes += f" {manager.IndexToNode(node)}" print(dropped_nodes) # Display routes. time_dimension = routing.GetDimensionOrDie("Time") capacity_dimension = routing.GetDimensionOrDie("Capacity") total_distance = 0 total_time = 0 total_load = 0 for vehicle_id in range(manager.GetNumberOfVehicles()): nodes_visited = [] # To Keep Track of Node Visited by Vehicle index = routing.Start(vehicle_id) plan_output = f"Route for vehicle {vehicle_id}:\n" route_distance = 0 nodes_visited.append(manager.IndexToNode(index)) while not routing.IsEnd(index): time_var = time_dimension.CumulVar(index) capacity_var = capacity_dimension.CumulVar(index) plan_output += ( f"Node_{manager.IndexToNode(index)}" f" {route_distance}m" f" TW:[{time_var.Min()},{time_var.Max()}]" f" Time({solution.Min(time_var)},{solution.Max(time_var)})" f" Load({solution.Value(capacity_var)}/{capacity_var.Max()})" " -> " ) previous_index = index index = solution.Value(routing.NextVar(index)) nodes_visited.append(manager.IndexToNode(index)) route_distance += routing.GetArcCostForVehicle( previous_index, index, vehicle_id ) if len(nodes_visited) > 2: # Condition does not prints vehicels that are not assigned time_var = time_dimension.CumulVar(index) capacity_var = capacity_dimension.CumulVar(index) plan_output += ( f"Node_{manager.IndexToNode(index)}" f" {route_distance}m" f" Time({solution.Min(time_var)},{solution.Max(time_var)})" f" Load({solution.Value(capacity_var)}/{capacity_var.Max()})" "\n" ) plan_output += f"Distance of the route: {route_distance}m\n" plan_output += f"Time of the route: {solution.Min(time_var)}min\n" plan_output += f"Load of the route: {solution.Value(capacity_var)}\n" print(plan_output) total_distance += route_distance total_time += solution.Min(time_var) total_load += solution.Value(capacity_var) print(nodes_visited) print(f"Total distance of all routes: {total_distance}m") print(f"Total time of all routes: {total_time}min") print(f"Total load of all routes: {total_load}") # print(f"Total Distance of all routes: {total_distance}m") def main(): data = create_data_model() manager = pywraprouting.RoutingIndexManager( data["num_Locations"], data["num_vehicles"], data["depot"] ) routing = pywraprouting.RoutingModel(manager) def distance_callback(from_index, to_index): from_node = manager.IndexToNode(from_index) to_node = manager.IndexToNode(to_index) if from_node in range(data["duplicate_nodes"], data["num_Locations"]): from_node = 0 if to_node in range(data["duplicate_nodes"], data["num_Locations"]): to_node = 0 return data["distance_matrix"][from_node][to_node] data_callback_index = routing.RegisterTransitCallback(distance_callback) routing.SetArcCostEvaluatorOfAllVehicles(data_callback_index) def demand_callback(from_index): from_node = manager.IndexToNode(from_index) return data["demands"][from_node] demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback) capacity = "Capacity" routing.AddDimensionWithVehicleCapacity( demand_callback_index, 0, data["vehicle_capacity"], True, capacity ) capacity_dimension = routing.GetDimensionOrDie(capacity) def time_callback(from_index, to_index): from_node = manager.IndexToNode(from_index) to_node = manager.IndexToNode(to_index) if from_node in range(data["duplicate_nodes"], data["num_Locations"]): from_node = 0 if to_node in range(data["duplicate_nodes"], data["num_Locations"]): to_node = 0 return data["duration_matrix"][from_node][to_node] time_callback_index = routing.RegisterTransitCallback(time_callback) time_dim = "Time" routing.AddDimension( time_callback_index, 300_000, 100_000_000_000, # Some Big Number so that Model should not limit itself. False, time_dim, ) time_dimension = routing.GetDimensionOrDie(time_dim) for location_idx, time_window in enumerate(data["time_windows"]): if location_idx == 0: continue index = manager.NodeToIndex(location_idx) time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1]) routing.AddToAssignment(time_dimension.SlackVar(index)) for vehicle_id in range(data["num_vehicles"]): index = routing.Start(vehicle_id) time_dimension.CumulVar(index).SetRange( data["time_windows"][0][0], data["time_windows"][0][1] ) routing.AddToAssignment(time_dimension.SlackVar(index)) for i in range(data["num_vehicles"]): routing.AddVariableMinimizedByFinalizer( time_dimension.CumulVar(routing.Start(i)) ) routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.End(i))) for request in data["pickup_dropoff"]: pickup_index = manager.NodeToIndex(request[0]) delivery_index = manager.NodeToIndex(request[1]) routing.solver().Add( routing.VehicleVar(pickup_index) == routing.VehicleVar(delivery_index) ) routing.solver().Add( time_dimension.CumulVar(pickup_index) <= time_dimension.CumulVar(delivery_index) ) # Not Sure about whether this is right or wrong. Added Here Baesd Upon the issue #685 min_dur = time_callback(pickup_index, delivery_index) max_dur = int(1.3 * min_dur) dur_expr = time_dimension.CumulVar(delivery_index) - time_dimension.CumulVar( index ) routing.solver().Add(dur_expr <= max_dur) # Consraint End----------- routing.AddPickupAndDelivery(pickup_index, delivery_index) routing.AddDisjunction([pickup_index, delivery_index], 20_000, 2) search_parameters = pywraprouting.DefaultRoutingSearchParameters() search_parameters.first_solution_strategy = ( FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION ) search_parameters.local_search_metaheuristic = ( LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH ) search_parameters.time_limit.FromSeconds(3) # search_parameters.log_search = True solution = routing.SolveWithParameters(search_parameters) print_solution(manager, routing, solution) if __name__ == "__main__": main() This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,175 @@ ```diff %diff -u --color main.py cvrptw_pd.py --- main.py 2024-07-04 16:11:07.524848863 +0200 +++ cvrptw_pd.py 2024-07-04 16:10:16.518365568 +0200 @@ -17,8 +17,12 @@ """ import numpy as np -from ortools.constraint_solver import routing_enums_pb2 -from ortools.constraint_solver import pywrapcp +from ortools.routing import enums_pb2 +from ortools.routing import pywraprouting + +FirstSolutionStrategy = enums_pb2.FirstSolutionStrategy +LocalSearchMetaheuristic = enums_pb2.LocalSearchMetaheuristic +RoutingSearchStatus = enums_pb2.RoutingSearchStatus def create_data_model(): @@ -86,47 +90,89 @@ return data -def print_solution(data, manager, routing, solution): +def print_solution(manager, routing, solution): """Prints solution on console.""" + status = routing.status() + print(f"Status: {RoutingSearchStatus.Value.Name(status)}") + if ( + status != RoutingSearchStatus.ROUTING_OPTIMAL + and status != RoutingSearchStatus.ROUTING_SUCCESS + ): + print("No solution found!") + return print(f"Objective: {solution.ObjectiveValue()}") + # Display dropped nodes. + dropped_nodes = "Dropped nodes:" + for node in range(routing.Size()): + if routing.IsStart(node) or routing.IsEnd(node): + continue + if solution.Value(routing.NextVar(node)) == node: + dropped_nodes += f" {manager.IndexToNode(node)}" + print(dropped_nodes) + # Display routes. + time_dimension = routing.GetDimensionOrDie("Time") + capacity_dimension = routing.GetDimensionOrDie("Capacity") total_distance = 0 - for vehicle_id in range(data["num_vehicles"]): - nodes_visited = [] # To Keep Track of Vehicles Visited by Vehicle + total_time = 0 + total_load = 0 + for vehicle_id in range(manager.GetNumberOfVehicles()): + nodes_visited = [] # To Keep Track of Node Visited by Vehicle index = routing.Start(vehicle_id) plan_output = f"Route for vehicle {vehicle_id}:\n" route_distance = 0 nodes_visited.append(manager.IndexToNode(index)) while not routing.IsEnd(index): - node = manager.IndexToNode(index) - plan_output += f" {node} -> " + time_var = time_dimension.CumulVar(index) + capacity_var = capacity_dimension.CumulVar(index) + plan_output += ( + f"Node_{manager.IndexToNode(index)}" + f" {route_distance}m" + f" TW:[{time_var.Min()},{time_var.Max()}]" + f" Time({solution.Min(time_var)},{solution.Max(time_var)})" + f" Load({solution.Value(capacity_var)}/{capacity_var.Max()})" + " -> " + ) previous_index = index index = solution.Value(routing.NextVar(index)) nodes_visited.append(manager.IndexToNode(index)) route_distance += routing.GetArcCostForVehicle( previous_index, index, vehicle_id ) - if ( - len(nodes_visited) > 2 - ): # Condition does not prints vehicels that are not assigned - plan_output += f"{manager.IndexToNode(index)}\n" + if len(nodes_visited) > 2: # Condition does not prints vehicels that are not assigned + time_var = time_dimension.CumulVar(index) + capacity_var = capacity_dimension.CumulVar(index) + plan_output += ( + f"Node_{manager.IndexToNode(index)}" + f" {route_distance}m" + f" Time({solution.Min(time_var)},{solution.Max(time_var)})" + f" Load({solution.Value(capacity_var)}/{capacity_var.Max()})" + "\n" + ) plan_output += f"Distance of the route: {route_distance}m\n" + plan_output += f"Time of the route: {solution.Min(time_var)}min\n" + plan_output += f"Load of the route: {solution.Value(capacity_var)}\n" print(plan_output) total_distance += route_distance + total_time += solution.Min(time_var) + total_load += solution.Value(capacity_var) print(nodes_visited) + print(f"Total distance of all routes: {total_distance}m") + print(f"Total time of all routes: {total_time}min") + print(f"Total load of all routes: {total_load}") # print(f"Total Distance of all routes: {total_distance}m") def main(): data = create_data_model() - manager = pywrapcp.RoutingIndexManager( + manager = pywraprouting.RoutingIndexManager( data["num_Locations"], data["num_vehicles"], data["depot"] ) - routing = pywrapcp.RoutingModel(manager) + routing = pywraprouting.RoutingModel(manager) def distance_callback(from_index, to_index): from_node = manager.IndexToNode(from_index) - to_node = manager.IndexToNode(to_node) + to_node = manager.IndexToNode(to_index) if from_node in range(data["duplicate_nodes"], data["num_Locations"]): from_node = 0 if to_node in range(data["duplicate_nodes"], data["num_Locations"]): @@ -148,9 +194,6 @@ ) capacity_dimension = routing.GetDimensionOrDie(capacity) - for node in range(data["num_Locations"]): - routing.AddDisjunction([manager.NodeToIndex(node)], 100) - def time_callback(from_index, to_index): from_node = manager.IndexToNode(from_index) to_node = manager.IndexToNode(to_index) @@ -165,8 +208,8 @@ time_dim = "Time" routing.AddDimension( time_callback_index, - 300, - 100000000000, # Some Big Number so that Model should not limit itself. + 300_000, + 100_000_000_000, # Some Big Number so that Model should not limit itself. False, time_dim, ) @@ -214,24 +257,20 @@ # Consraint End----------- routing.AddPickupAndDelivery(pickup_index, delivery_index) - search_parameters = pywrapcp.DefaultRoutingSearchParameters() + routing.AddDisjunction([pickup_index, delivery_index], 20_000, 2) + + search_parameters = pywraprouting.DefaultRoutingSearchParameters() search_parameters.first_solution_strategy = ( - routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION + FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION ) search_parameters.local_search_metaheuristic = ( - routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH + LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH ) - search_parameters.time_limit.seconds = 30 + search_parameters.time_limit.FromSeconds(3) # search_parameters.log_search = True solution = routing.SolveWithParameters(search_parameters) - - if solution: - print("Solution Found") - print_solution(data, manager, routing, solution) - - else: - print("NO SOLUTION") + print_solution(manager, routing, solution) if __name__ == "__main__": ``` This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,23 @@ ```sh python /tmp/cvrptw_pd.py Status: ROUTING_SUCCESS Objective: 268314 Dropped nodes: 1 5 6 8 9 10 12 15 16 17 21 22 24 25 26 28 31 32 Route for vehicle 0: Node_0 0m TW:[0,86400] Time(0,0) Load(0/0) -> Node_3 7741m TW:[23400,25200] Time(23400,24121) Load(0/3) -> Node_19 15009m TW:[0,86400] Time(23915,24636) Load(1/3) -> Node_2 23228m TW:[23400,25200] Time(24479,25200) Load(0/3) -> Node_11 24449m TW:[36000,36000] Time(36000,36000) Load(1/3) -> Node_14 28793m TW:[39600,39600] Time(39600,39600) Load(2/3) -> Node_18 40504m TW:[0,86400] Time(40455,40455) Load(3/3) -> Node_27 40504m TW:[0,86400] Time(40455,40455) Load(2/3) -> Node_30 40504m TW:[0,86400] Time(40455,40455) Load(1/3) -> Node_0 40504m Time(40455,40455) Load(0/3) Distance of the route: 40504m Time of the route: 40455min Load of the route: 0 [0, 3, 19, 2, 11, 14, 18, 27, 30, 0] Route for vehicle 3: Node_0 0m TW:[0,86400] Time(0,0) Load(0/0) -> Node_4 21036m TW:[23400,25200] Time(23400,25200) Load(0/3) -> Node_7 25327m TW:[28800,28800] Time(28800,28800) Load(1/3) -> Node_13 35440m TW:[39600,39600] Time(39600,39600) Load(2/3) -> Node_23 47810m TW:[0,86400] Time(40513,40513) Load(3/3) -> Node_20 47810m TW:[0,86400] Time(40513,40513) Load(2/3) -> Node_29 47810m TW:[0,86400] Time(40513,40513) Load(1/3) -> Node_0 47810m Time(40513,40513) Load(0/3) Distance of the route: 47810m Time of the route: 40513min Load of the route: 0 [0, 4, 7, 13, 23, 20, 29, 0] Total distance of all routes: 88314m Total time of all routes: 80968min Total load of all routes: 0 ```