AI-generated Key Takeaways
-
loadDemandsspecify the load a shipment requires, whileloadLimitsspecify the maximum load a vehicle can handle. -
Both
loadDemandsandloadLimitsare defined using types, which can represent weight, volume, or other custom categories. -
Shipments are assigned to vehicles based on their load demands and the vehicles' load limits, ensuring efficient capacity utilization.
-
The
OptimizeToursResponseprovides details on vehicle loads at different points in the route, reflecting load transfers during pickups and deliveries. -
In addition to hard limits, soft load limits can be used to model preferences or costs associated with exceeding a preferred load threshold.
This guide describes loadDemands and loadLimits, and how they relate to each
other.
As mentioned in Pickup and Delivery Time Window Constraints, the
OptimizeToursRequest message (REST, gRPC) contains a number of
properties that specify constraints on the problem being optimized. Several
OptimizeToursRequest properties represent load constraints.
Vehicles and shipments have physical properties that must be considered when planning a route.
- Vehicles: The
loadLimitsproperty specifics the maximum load the vehicle can handle. See theVehiclemessage's (REST, gRPC) documentation. - Shipments: The
loadDemandsproperty specifies how much load a given shipment consumes. See theShipmentmessage's (REST, gRPC) documentation.
Together, these two constraints make it possible for the optimizer to appropriately assign shipments to vehicles in a manner that best matches your fleet capacity and shipment demands.
This rest of this document discusses loadLimits and loadDemands in detail.
Load demands and limits: types
You express each load demand and limit constraint in terms of a type.
You can provide your own set of load types, like the following examples:
- weight
- volume
- linear measurements
- names of items or equipment being transported
This guide uses weightKg as an example type.
Both Shipment.loadDemands and Vehicle.loadLimits use the Protocol Buffers
map type, with string keys that represent the types of load.
Shipment.loadDemands values use the Load message (REST, gRPC).
The Load message has a single amount property representing how much capacity
is required to complete the shipment in the specified type.
Vehicle.loadLimits values use the LoadLimit message (REST,
gRPC). The LoadLimit message has several properties, with maxLoad
representing the vehicle's maximum load capacity in the specified type.
A shipment's loadDemands consumes its assigned vehicle's loadLimits only if
the two have matching load type keys. For example, a shipment with
loadDemands of:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
requires 50 load units in the weightKg type for the shipment to be
completed. A vehicle with loadLimits of:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
may be able to complete the shipment, as the vehicle's maxLoad in the
weightKg type is greater than or equal to the shipment's loadDemands in
the weightKg type. However, a vehicle with loadLimits of:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
implicitly has unlimited weightKg capacity due to the absence of a
weightKg load limit, so the vehicle is not constrained by the shipment's
weight demand.
Load transfer between shipments and vehicles
As shipments are picked up and delivered by vehicles, the shipment's
loadDemand transfers between the shipment and the vehicle. You can see the
vehicle's loads in the OptimizeToursResponse message's (REST,
gRPC)routes.transitions entry for a given vehicle. The sequence is as
follows:
- The required load capacity is defined for the shipment as a
loadDemand. - The shipment is picked up by its assigned vehicle and the vehicle's
vehicleLoadsincreases by the amount of the shipment'sloadDemand. This transfer is represented by positivevisits.loadDemandsin the response message. - The vehicle delivers the shipment and the vehicle's
vehicleLoadsdecreases by the amount of the delivered shipment'sloadDemand. This transfer is represented by negativevisits.loadDemandsin the response message.
A vehicle's vehicleLoads cannot exceed its specified loadLimits at any point
on its route.
A complete example with load demands and limits
See an example request with load demands and limits
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0, "loadDemands": { "weightKg": { "amount": 50 } } }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 15.0, "loadDemands": { "weightKg": { "amount": 10 } } }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0, "loadDemands": { "weightKg": { "amount": 80 } } } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0, "loadLimits": { "weightKg": { "maxLoad": 100 } } } ] } }
The example request contains several load-related parameters:
shipments[0]has a load demand of 50weightKg.shipments[1]has a load demand of 10weightKg.shipments[2]has a load demand of 80weightKg.vehicles[0]has a load limit of 100weightKg.
See a response to the request with load demands and limits
{ "routes": [ { "vehicleStartTime": "2023-01-13T16:00:00Z", "vehicleEndTime": "2023-01-13T16:43:27Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T16:00:00Z", "detour": "0s", "loadDemands": { "weightKg": { "amount": "50" } } }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T16:02:30Z", "detour": "150s", "loadDemands": { "weightKg": { "amount": "10" } } }, { "startTime": "2023-01-13T16:08:55Z", "detour": "150s", "loadDemands": { "weightKg": { "amount": "-50" } } }, { "shipmentIndex": 1, "startTime": "2023-01-13T16:16:37Z", "detour": "343s", "loadDemands": { "weightKg": { "amount": "-10" } } }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T16:27:07Z", "detour": "1627s", "loadDemands": { "weightKg": { "amount": "80" } } }, { "shipmentIndex": 2, "startTime": "2023-01-13T16:36:26Z", "detour": "0s", "loadDemands": { "weightKg": { "amount": "-80" } } } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T16:00:00Z", "vehicleLoads": { "weightKg": {} } }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T16:02:30Z", "vehicleLoads": { "weightKg": { "amount": "50" } } }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-13T16:05:00Z", "vehicleLoads": { "weightKg": { "amount": "60" } } }, { "travelDuration": "212s", "travelDistanceMeters": 791, "waitDuration": "0s", "totalDuration": "212s", "startTime": "2023-01-13T16:13:05Z", "vehicleLoads": { "weightKg": { "amount": "10" } } }, { "travelDuration": "380s", "travelDistanceMeters": 1190, "waitDuration": "0s", "totalDuration": "380s", "startTime": "2023-01-13T16:20:47Z", "vehicleLoads": { "weightKg": {} } }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T16:29:37Z", "vehicleLoads": { "weightKg": { "amount": "80" } } }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-13T16:40:36Z", "vehicleLoads": { "weightKg": {} } } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "1407s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2607s", "travelDistanceMeters": 4812, "maxLoads": { "weightKg": { "amount": "80" } } }, "routeCosts": { "model.vehicles.cost_per_kilometer": 48.12, "model.vehicles.cost_per_hour": 28.966666666666665 }, "routeTotalCost": 77.086666666666659 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1407s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2607s", "travelDistanceMeters": 4812, "maxLoads": { "weightKg": { "amount": "80" } } }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T16:00:00Z", "latestVehicleEndTime": "2023-01-13T16:43:27Z", "totalCost": 77.086666666666659, "costs": { "model.vehicles.cost_per_hour": 28.966666666666665, "model.vehicles.cost_per_kilometer": 48.12 } } }
The added load constraints affect the order of visits:
shipment[0]is picked upshipment[1]is picked upshipment[0]is deliveredshipment[1]is deliveredshipment[2]is picked upshipment[2]is delivered
This order reflects that three shipments cannot be completed by the vehicle at
the same time because their total loadDemands exceed the vehicle's
loadLimits.
Each visits entry includes the change in vehicle load resulting from the
completion of the Visit. Positive load values represent shipment loading while
negative values represent shipment unloading.
Each transitions entry includes the total vehicle load during the
Transition. transitions[2], for example, has a weightKg load of 60,
representing the combined loads of shipment[0] and shipment[1].
Metrics objects routes[0].metrics and metrics.aggregatedRouteMetrics include
a maxLoads property. The value for type weightKg is 80, representing
the portion of the vehicle's route that transported shipments[2] to its
delivery location.
Soft load limit constraints
As with time windows described in Pickup and Delivery Time Window
Constraints, load limit constraints have hard and soft variants. The
LoadLimit message's maxLoad property expresses a hard constraint: the
vehicle must never carry load exceeding the maxLoad value in the specified
type. Properties softMaxLoad and costPerUnitAboveSoftMax express a soft
constraint, with every unit exceeding softMaxLoad incurring a
costPerUnitAboveSoftMax cost.
Soft load limit constraints have several uses, such as:
- balancing shipments across more vehicles than the minimum number necessary when it is cost effective to do so
- expressing driver preference for the number of items they can comfortably pickup and deliver on a given route
- loading vehicles below their maximum physical capacity to limit wear and reduce maintenance costs
Hard and soft load limit constraints can be used together. For example, a hard load limit might express the maximum weight of cargo a vehicle can safely carry or the maximum number of items that will fit in a vehicle at one time, while a soft load limit might be the maximum weight or number of items that would tax the driver's ability to fit everything in the vehicle.