Efficiently Estimating Travel Time
Step 1: choose depot to first pick-up with shortest travel time Heuristic 1++ D A A B B C C D Step 1: choose depot to first pick-up with shortest travel time Call m3 find_path from every depot to every pick-up? 0.1s * N * M 0.1s * 100 * 10 = 100s already too long!
1. Use geometric distance to estimate travel time? Ideas? 1. Use geometric distance to estimate travel time? And only call find_path at end, with final order? Reasonable, but will not be perfectly accurate Will cost us some quality
Inaccurate travel time estimate Time estimate: ~300 m / 60 km per hour Real time: much higher
Ideas? 2. Pre-compute all shortest paths you might need? Then just look up delays during optimization? How many shortest paths to pre-compute? Using single-source to single-dest find_path: Need any delivery location to any other travel time: 2N * (2N-1) 39,800 calls for N = 100 Plus any depot to any delivery location M * 2N 2000 calls for N = 100, M = 10 Plus any delivery location to any depot 2N * M 2000 calls Total: 43,800 calls to your find_path 0.1 s per call 4380 s too slow
Dijkstra’s Algorithm What do we know at this point? Shortest path to every intersection in the blue circle
Dijkstra’s Algorithm Keep Going! Until all destinations reached Then backtrace from each to find path
Pre-Computing Travel Time Paths Using single-source to all destinations Need any delivery location to any other 2N calls 200 if N = 100 Plus any depot to any delivery location M calls 10 Plus any delivery location to any depot 0 calls Total: 210 calls Is this the minimum? No. Any depot to any delivery location: One call with multi-source to all destinations Reduces to 201 path searches Get from earlier call
Is This Fast Enough? Recall: Total: Dijkstra’s algorithm can search whole graph And usually will with multiple destinations O(N) items to put in wavefront Using heap / priority_queue: O (log N) to add / remove 1 item from wavefront Total: N log N Can execute in ~0.1 s OK!
Heuristic 3: Iterative Improvement
Heuristic 3: Iterative Improvement Improve an existing solution? C B A A B D C D
Heuristic 3: Iterative Improvement Improve an existing solution? How? Local perturbation C B 8 15 5 A 18 B A 5 4 20 D C 4 2 D Travel time for this connection (edge) Total travel time = 81
Heuristic 3: Local Perturbation E.g., swap order of B and C drop offs C B 8 15 5 A 18 B A 5 4 20 D C 4 2 D Total travel time = 81
Heuristic 3: Local Perturbation Legal? Compute new travel times New travel time: 72 Better update solution C B 8 14 23 5 A B A 5 4 7 D C 4 2 D Old travel time = 81
Heuristic 3: Local Perturbation More powerful perturbation? Swapping two intersections limited change Maybe bigger improvements possible with more radical perturbation? 8 14 23 5 5 4 7 4 2
Heuristic 3: Local Perturbation E.g. 2-edge operation (2-opt) Delete two connections in path 8 14 23 5 5 4 7 4 2
Heuristic 3: Local Perturbation Reconnect path differently 8 5 4 4 2
Heuristic 3: Local Perturbation May have to reverse order of part of the path to make legal May need to fix up depots to make legal 8 5 4 4 2
Heuristic 3: Local Perturbation Recalculate travel time Update solution if better than previous New travel time: 70 (better than prior 71) 18 8 15 5 4 12 4 4
Anything Else? Classic traveling salesman: no Our traveling courier Check if path is legal delivery order Have to pick up package before dropping off Can’t overload truck Traveling salesman 2-opt works very well Traveling courier? May get less gain due to legality constraints
Intersection Exchange vs. 2-Opt Escaping Local Minima Intersection Exchange vs. 2-Opt
Say We’re In This State Local perturbation to improve? 3 1 2 4 7 5 8 6 3 1 2 4 7 5 8 6 9 Local perturbation to improve?
Swap Order of Two Deliveries? 3 1 2 4 7 5 8 6 9 No swap of two deliveries can improve! Stuck in a local minimum
2-Opt? 3 1 2 4 7 5 8 6 9 Path cut into 3 pieces
2-Opt? 3 1 2 4 7 5 8 6 9 Reconnected: worse!
2-Opt? 3 1 2 4 Reconnected differently: now better! 7 5 8 6 9 More powerful permutation operator can escape more local minima
Representing the Solution
Travel Order: How to Represent? Store whole route (need for final solution) vector<CourierSubpath> struct CourierSubpath { unsigned start_intersection; unsigned end_intersection; vector<unsigned> subpath; // Street segment ids vector<unsigned> pickUp_indices; // items to pick up } end_intersection = 28 pickUp_indices = {} pickUp_indices = {2} pickUp_indices = {2, 5} subpath = {97, 58, …} start_intersection = 53
Solution Representation Given N pick up / drop offs 2 1 3 0 2 3 2 0 1 1 One courierSubpath Given M courier truck depots (intersections)
Travel Order: How to Represent? 2. Better for optimization: order of deliveries Turn into a full route only when needed Faster & easier to change order
Solution Representation Given N pick up / drop offs 2 1 3 0 2 3 2 0 1 1 Given M courier truck depots (intersections) vector<pickOrDrop> deliveryOrder; deliveryOrder = {0, 0, 1, 3, 3, 1, 2, 2} , , }
Solution Representation What About Depots? Solution Representation Given N pick up / drop offs 2 1 3 0 2 3 2 0 1 1 Given M courier truck depots (intersections) Could store: vector<pickDropDepot> deliveryOrder; deliveryOrder = {0, 0, 0, 1, 3, 3, 1, 2, 2, 2}
Solution Representation What About Depots? Solution Representation Given N pick up / drop offs 2 1 3 0 2 3 2 0 1 1 Given M courier truck depots (intersections) Don’t have to store depots Could fill in closest depot to start/end later deliveryOrder = {0, 0, 0, 1, 3, 3, 1, 2, 2, 2}