VRPTW: Time Windows

๐Ÿ”ฅ Vibe Prompt

"Solve VRPTW: 9 locations with time windows, 3 vehicles. Each customer has an earliest/latest delivery time."

data = {
    "time_matrix": [[0,6,9,...],[6,0,8,...],...],
    "time_windows": [(0,60),(5,20),(10,30),...],
    "num_vehicles": 3,
    "depot": 0
}

# Add Time dimension
routing.AddDimension(transit_callback_index, 30, 60, False, "Time")
time_dimension = routing.GetDimensionOrDie("Time")

# Set time windows for each customer
for location_idx, (early, late) in enumerate(data["time_windows"]):
    if location_idx == data["depot"]:
        continue
    index = manager.NodeToIndex(location_idx)
    time_dimension.CumulVar(index).SetRange(early, late)

This is the core algorithm behind UberEats & Foodpanda!

When you order food, the system solves VRPTW in real-time to assign the best driver.

Chapter Summary

  • Understand core concepts and principles
  • Master implementation methods and techniques
  • Familiar with common issues and solutions
  • Able to apply in real projects

Further Reading

  • Official documentation and API references
  • Open source examples on GitHub
  • Technical books and online courses
  • Community discussions and tech blogs

Implementation Example

Basic Example

# This section provides a complete implementation example

Steps

  1. Setup: Configure development environment
  2. Data: Prepare required data
  3. Implementation: Build core functionality
  4. Testing: Verify correctness
  5. Optimization: Improve performance

Common Errors

| Error Type | Cause | Solution | |------------|-------|----------| | Compilation | Syntax | Check code syntax | | Runtime | Environment | Verify dependencies installed | | Logic | Algorithm | Step-by-step debugging | | Performance | Efficiency | Use profilers |

Code Example

import sys

def main():
    print("Hello, World!")

if __name__ == "__main__":
    main()

References

  • Official documentation
  • API reference
  • Open source examples
  • Community discussions

Key Points

  • Understand the core concepts thoroughly
  • Practice with hands-on code examples
  • Apply knowledge to real-world problems
  • Review and reinforce through exercises

Further Learning

  • Official documentation
  • Open source projects on GitHub
  • Community forums and discussions
  • Related courses and tutorials

Time Window Constraints

In VRPTW, each customer i has:

  • ready_time[i]: earliest time the vehicle can arrive (e_i)
  • due_time[i]: latest time the vehicle can arrive (l_i)
  • service_time[i]: time spent at the customer (s_i)

The vehicle can arrive before e_i but must wait until e_i to start service. Arriving after l_i is not allowed.

VRPTW Formulation

Minimize: total distance traveled
Subject to:
  - All customers visited once
  - Each route starts and ends at depot
  - Vehicle capacity not exceeded
  - arrival_time[i] >= ready_time[i]
  - arrival_time[i] <= due_time[i]
  - departure_time[i] = arrival_time[i] + service_time[i]
  - travel_time[i][j] = distance[i][j] / speed

Time Window Types

| Type | Description | Example | |------|-------------|---------| | Hard | Must arrive before due time | Doctor appointments | | Soft | Can arrive late with penalty | Delivery windows | | Mixed | Some hard, some soft | Food delivery (hot food) |

Insertion Heuristic for VRPTW

def vrptw_insertion(customers, vehicles, dist_matrix, capacity):
    """
    Sequential insertion heuristic for VRPTW.
    Inserts each customer into the best feasible position.
    """
    unvisited = set(range(len(customers)))
    routes = [[] for _ in range(len(vehicles))]
    route_loads = [0] * len(vehicles)
    route_times = [[0.0] for _ in range(len(vehicles))]  # current time at each stop
    
    for customer in sorted(unvisited, key=lambda c: customers[c].due_time):
        best_cost = float('inf')
        best_route = -1
        best_position = -1
        
        for r_idx in range(len(vehicles)):
            if route_loads[r_idx] + customers[customer].demand > vehicles[r_idx].capacity:
                continue
            
            route = routes[r_idx]
            for pos in range(len(route) + 1):
                if is_feasible_insertion(route, pos, customer, customers, dist_matrix, route_times[r_idx]):
                    cost = calculate_insertion_cost(route, pos, customer, dist_matrix)
                    if cost < best_cost:
                        best_cost = cost
                        best_route = r_idx
                        best_position = pos
        
        if best_route >= 0:
            routes[best_route].insert(best_position, customer)
            route_loads[best_route] += customers[customer].demand
            update_route_times(routes[best_route], customers, dist_matrix, route_times[best_route])
            unvisited.remove(customer)
    
    return routes


def is_feasible_insertion(route, pos, customer, customers, dist_matrix, times):
    """Check if inserting customer at pos preserves all time window constraints."""
    # Simplified check โ€” real implementation must verify all downstream times
    prev = route[pos - 1] if pos > 0 else -1  # -1 = depot
    next_c = route[pos] if pos < len(route) else -1
    
    prev_node = prev + 1  # +1 for depot offset
    cust_node = customer + 1
    next_node = next_c + 1 if next_c >= 0 else 0
    
    arrival = times[pos] + dist_matrix[prev_node][cust_node]
    if arrival > customers[customer].due_time:
        return False
    
    departure = max(arrival, customers[customer].ready_time) + customers[customer].service_time
    
    if next_c >= 0:
        arrival_next = departure + dist_matrix[cust_node][next_node]
        if arrival_next > customers[next_c].due_time:
            return False
    else:
        arrival_depot = departure + dist_matrix[cust_node][0]
        # No depot time window, always feasible
    
    return True

OR-Tools VRPTW Implementation

from ortools.constraint_solver import routing_enums_pb2, pywrapcp

def solve_vrptw_ortools(data):
    """Solve VRPTW using Google OR-Tools."""
    manager = pywrapcp.RoutingIndexManager(
        len(data['distance_matrix']),
        data['num_vehicles'],
        0  # depot
    )
    routing = pywrapcp.RoutingModel(manager)
    
    # Distance callback
    def distance_callback(from_i, to_i):
        return data['distance_matrix'][manager.IndexToNode(from_i)][manager.IndexToNode(to_i)]
    transit_cb = routing.RegisterTransitCallback(distance_callback)
    routing.SetArcCostEvaluatorOfAllVehicles(transit_cb)
    
    # Add distance dimension (for total route distance)
    routing.AddDimension(transit_cb, 0, 3000, True, 'Distance')
    
    # Time callback
    def time_callback(from_i, to_i):
        return data['distance_matrix'][manager.IndexToNode(from_i)][manager.IndexToNode(to_i)]
    time_cb = routing.RegisterTransitCallback(time_callback)
    routing.AddDimension(time_cb, 30, 3000, False, 'Time')
    
    time_dimension = routing.GetDimensionOrDie('Time')
    for node in range(1, len(data['time_windows'])):
        start = data['time_windows'][node][0]
        end = data['time_windows'][node][1]
        time_dimension.CumulVar(node).SetRange(start, end)
    
    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (
        routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
    )
    
    solution = routing.SolveWithParameters(search_parameters)
    return solution, manager, routing

Applications

| Industry | Time Window Example | |----------|-------------------| | Food Delivery | "Deliver between 12:00-12:30" (30 min window) | | Medical | "Appointment at 14:00" (hard window) | | E-commerce | "Deliver between 9:00-17:00" (wide window) | | Field Service | "Repair between 10:00-12:00" (narrow window) | | Waste Collection | "Collect before 8:00 AM" (deadline) |

Summary

VRPTW adds time windows to the VRP. Each customer has a ready time and a due time. Hard windows must be strictly met; soft windows allow late arrivals with a penalty. Insertion heuristics build feasible routes, and OR-Tools finds optimal solutions for small instances.

Key takeaways:

  • VRPTW: each customer has [ready_time, due_time] window
  • Hard windows: must arrive before due time
  • Soft windows: can be late with penalty
  • Insertion heuristic: place in best feasible position
  • OR-Tools: optimal for small instances
  • Time dimension tracks cumulative travel time
  • Applications: food delivery, medical, field service

What's Next: Large-Scale VRP

The next chapter covers large-scale VRP โ€” decomposition strategies, cluster-first-route-second, and metaheuristics for problems with hundreds of customers.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!