Vehicle Capacity and Node Demand
In Vehicle Routing Problems (VRP), vehicle capacity and node demand are fundamental constraints that define the problem's boundaries. The optimizer's goal is to create the most efficient routes while ensuring that the vehicle's capacity is not exceeded at any point along its route.
SWAT's optimization APIs support multi-dimensional capacity, allowing you to model real-world constraints beyond simple weight or volume.
-
Vehicle Capacity: This is defined on the
vehicleobject as a dictionary of key-value pairs. Each key represents a dimension of capacity (e.g.,units,special_handling), and the value is the maximum amount that vehicle can carry. -
Node Demand: This is defined on the
nodeobject, also as a dictionary. For a Pickup and Delivery (PDP) model, demand is expressed as:- Positive values at
pickupnodes, which increase the vehicle's load. - Negative values at
dropoffnodes, which decrease the vehicle's load.
- Positive values at
For the optimizer to consider assigning a booking to a vehicle, all demand keys on the nodes must have a corresponding capacity key on the vehicle.
How Capacity Matching Works in PDP
The optimizer checks for two conditions before and during route construction:
-
Dimension Matching: Does the vehicle have capacity for every type of demand the booking requires? If a booking's nodes require a
special_handlingdemand, but the vehicle does not have this capacity defined, that booking can never be assigned to that vehicle. -
Capacity Limits: Will the vehicle's capacity be exceeded at any point? The optimizer tracks the vehicle's load dynamically. After each
pickup, the load increases, and it must not exceed the vehicle's capacity. After eachdropoff, the load decreases.
This allows for sophisticated fleet management where, for example, only refrigerated trucks can be assigned to orders requiring cold storage.
Example
Here is a simplified PDP example demonstrating these concepts.
- The Vehicle: Has a capacity for
units(20), but no capacity forspecial_handling. - Booking A: Has a demand of 15
units. - Booking B: Has a demand of 10
units. The optimizer must choose between serving Booking A or Booking B, as serving both would exceed the vehicle's capacity (15 + 10 > 20). - Booking C: Has a demand for
special_handling. Because the vehicle does not have this capacity, this booking will be rejected.
{
"current_time": "2025-11-21T08:00:00Z",
"engine_settings": {
"calculation_parameters": {
"calculations_mode": "sync",
"scheduling_mode": "prebook"
},
"model_parameters": {
"optimize_quantity": "total_time"
},
"routing_engine": {
"routing_engine_name": "osrme",
"url": "http://mapbox-osrm-proxy",
"road_network": "van"
}
},
"nodes": [
{
"uid": "depot",
"node_type": "depot",
"lat": 1.3521,
"lon": 103.8198,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 0,
"demand": {}
},
{
"uid": "pickup_A",
"booking_uid": "booking_A",
"node_type": "pickup",
"lat": 1.38,
"lon": 103.85,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 300,
"demand": { "units": 15 },
"penalty": 100000
},
{
"uid": "dropoff_A",
"booking_uid": "booking_A",
"node_type": "dropoff",
"lat": 1.306,
"lon": 103.832,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 300,
"demand": { "units": -15 },
"penalty": 100000
},
{
"uid": "pickup_B",
"booking_uid": "booking_B",
"node_type": "pickup",
"lat": 1.29,
"lon": 103.85,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 300,
"demand": { "units": 10 },
"penalty": 100000
},
{
"uid": "dropoff_B",
"booking_uid": "booking_B",
"node_type": "dropoff",
"lat": 1.283,
"lon": 103.858,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 300,
"demand": { "units": -10 },
"penalty": 100000
},
{
"uid": "pickup_C",
"booking_uid": "booking_C",
"node_type": "pickup",
"lat": 1.35,
"lon": 103.93,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 300,
"demand": { "units": 5, "special_handling": 1 },
"penalty": 100000
},
{
"uid": "dropoff_C",
"booking_uid": "booking_C",
"node_type": "dropoff",
"lat": 1.34,
"lon": 103.92,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T20:00:00Z",
"close_time_ts_dynamic": "2025-11-21T20:00:00Z",
"service_time": 300,
"demand": { "units": -5, "special_handling": -1 },
"penalty": 100000
}
],
"vehicles": [
{
"agent_id": "vehicle_1",
"start_time": "2025-11-21T08:00:00Z",
"end_time": "2025-11-21T20:00:00Z",
"capacity": { "units": 20 },
"partial_route": ["depot"]
}
]
}
Playground
You can experiment with this PDP scenario in the playground below.
- Observe that Booking C is rejected because of the mismatched
special_handlingdemand. - Observe that the optimizer chooses to serve Booking A (15 units) and rejects Booking B (10 units), because serving both would exceed the vehicle's capacity of 20 units.
- Try adding
"special_handling": 1to the vehicle'scapacity. Booking C should now be served. - Try increasing the vehicle's
capacityforunitsto25or more. The optimizer should now be able to serve both Booking A and Booking B.