Pickup & Delivery¶
TQrouting supports mixed pickup and delivery operations on the same route. Vehicles can deliver goods to some customers and pick up goods from others — or do both at the same customer.
How It Works¶
The Pickup and Delivery mode is automatically activated when at least one customer has pickup_load greater than zero. If all customers only have delivery_load (and no pickup_load), the problem is treated as a standard Capacitated VRP.
In the pickup and delivery model:
- A vehicle starts its route fully loaded with all goods to be delivered along that route
- At delivery customers, the onboard load decreases
- At pickup customers, the vehicle picks up goods and the onboard load increases
- A customer may have both
delivery_loadandpickup_load— the delivery is performed first, then the pickup - The capacity constraint ensures that the peak onboard load at any point along the route does not exceed the vehicle's
capacity_load
Example¶
from tqrouting import TQRouter, VRPInstance, Customer, VehicleType, Location
router = TQRouter()
instance = VRPInstance(
customers=[
Customer(location=Location(matrix_id=1), delivery_load=8),
Customer(location=Location(matrix_id=2), pickup_load=5),
Customer(location=Location(matrix_id=3), delivery_load=6),
Customer(location=Location(matrix_id=4), delivery_load=3, pickup_load=4),
Customer(location=Location(matrix_id=5), delivery_load=7),
],
fleet=[
VehicleType(
start_location=Location(matrix_id=0),
end_location=Location(matrix_id=0),
capacity_load=25,
n_vehicles=3,
),
],
distance_matrix=[
[0, 2, 5, 8, 4, 1],
[2, 0, 7, 6, 3, 5],
[5, 7, 0, 4, 3, 6],
[8, 6, 4, 0, 2, 7],
[4, 3, 3, 2, 0, 5],
[1, 5, 6, 7, 5, 0],
],
)
solution = router.solve(instance)
for route in solution.routes:
print(f"Route {route.id}: delivery load = {route.route_delivery_load}")
for visit in route.visits:
print(f" Customer {visit.customer_id}")
Peak Onboard Load¶
The key difference from standard capacity constraints is that the solver tracks the peak onboard load rather than the simple sum of demands.
Consider a vehicle with capacity_load=20 visiting two customers:
- Customer A:
delivery_load=15(vehicle delivers 15 units) - Customer B:
pickup_load=10(vehicle picks up 10 units)
The vehicle starts with 15 units (to deliver to Customer A). After delivering to A, the load drops to 0. After picking up at B, the load rises to 10. The peak load is 15, which is within capacity.
If the order were reversed (pickup first, then deliver), the vehicle would start with 15 (for delivery) + 0 (no pickup goods yet), pick up 10 at B → peak is 25, exceeding capacity. The solver automatically finds the best order.
Mixed Load Customers¶
A single customer can have both delivery and pickup operations:
Customer(
location=Location(matrix_id=1),
delivery_load=10, # Deliver 10 units
pickup_load=5, # Then pick up 5 units
)
At this customer, the delivery is performed first (onboard load decreases by 10), then the pickup (onboard load increases by 5). The net change in onboard load is pickup_load - delivery_load = -5.
Reading Results¶
When pickup and delivery loads are used, the solution includes separate load breakdowns:
| Field | Description |
|---|---|
route.route_delivery_load |
Delivery load on this route |
route.route_pickup_load |
Pickup load on this route |
route.route_peak_load |
Maximum vehicle load at any point during the route |
solution.total_delivery_load |
Total delivery load across all routes |
solution.total_pickup_load |
Total pickup load across all routes |
Note
Unless the problem has a prize-collecting character, each customer's delivery_load or pickup_load should not exceed the capacity_load of the largest vehicle type.
Volume as a second dimension
Pickup and delivery work in two dimensions too. Add delivery_volume / pickup_volume on customers and capacity_volume on vehicles, and the peak-onboard-load rule is enforced independently per dimension. The load fields above are then returned as [weight, volume] lists. See Two-dimensional capacity.
Interactive Example
See the constraints notebook for a runnable pickup-and-delivery example.