Ce guide décrit loadDemands
et loadLimits
, ainsi que leur relation.
Comme indiqué dans la section Contraintes de période de ramassage et de livraison, le message OptimizeToursRequest
(REST, gRPC) contient un certain nombre de propriétés qui spécifient des contraintes sur le problème à optimiser. Plusieurs propriétés OptimizeToursRequest
représentent des contraintes de charge.
Les véhicules et les envois ont des propriétés physiques qui doivent être prises en compte lors de la planification d'un itinéraire.
- Véhicules: la propriété
loadLimits
spécifie la charge maximale que le véhicule peut supporter. Consultez la documentation du messageVehicle
(REST, gRPC). - Envois: la propriété
loadDemands
spécifie la charge consommée par un envoi donné. Consultez la documentation du messageShipment
(REST, gRPC).
Ensemble, ces deux contraintes permettent à l'optimiseur d'attribuer correctement les envois aux véhicules de manière à correspondre au mieux à la capacité de votre flotte et aux demandes d'expédition.
Le reste de ce document décrit loadLimits
et loadDemands
en détail.
Demandes et limites de charge: types
Vous exprimez chaque demande de charge et contrainte de limite en termes de type.
Vous pouvez fournir votre propre ensemble de types de charge, comme les exemples suivants:
- weight
- volume
- mesures linéaires
- noms des articles ou équipements transportés
Ce guide utilise weightKg
comme exemple de type.
Shipment.loadDemands
et Vehicle.loadLimits
utilisent le type map
des tampons de protocole, avec des clés string
qui représentent les types de charge.
Les valeurs Shipment.loadDemands
utilisent le message Load
(REST, gRPC).
Le message Load
comporte une seule propriété amount
représentant la capacité requise pour effectuer l'expédition du type spécifié.
Les valeurs Vehicle.loadLimits
utilisent le message LoadLimit
(REST, gRPC). Le message LoadLimit
comporte plusieurs propriétés, maxLoad
représentant la capacité de charge maximale du véhicule dans le type spécifié.
Le loadDemands
d'une expédition ne consomme le loadLimits
du véhicule qui lui est attribué que si les deux ont des clés de type de charge correspondantes. Par exemple, une expédition avec loadDemands
de:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
nécessite 50 unités de charge du type weightKg
pour que l'expédition soit effectuée. Véhicule avec loadLimits
:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
peut effectuer l'envoi, car la valeur maxLoad
du véhicule dans le type weightKg
est supérieure ou égale à la valeur loadDemands
de l'envoi dans le type weightKg
. Toutefois, un véhicule avec un loadLimits
de:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
La capacité weightKg
est illimitée en raison de l'absence de limite de charge weightKg
. Le véhicule n'est donc pas limité par la demande de poids de l'envoi.
Transfert de charge entre les expéditions et les véhicules
Lorsque les envois sont récupérés et livrés par des véhicules, l'loadDemand
de l'envoi est transféré entre l'envoi et le véhicule. Vous pouvez voir les charges du véhicule dans l'entrée routes.transitions
du message OptimizeToursResponse
(REST, gRPC) pour un véhicule donné. La séquence est la suivante:
- La capacité de charge requise est définie pour l'expédition en tant que
loadDemand
. - Le colis est récupéré par le véhicule qui lui est attribué, et le
vehicleLoads
du véhicule augmente du montant duloadDemand
du colis. Ce transfert est représenté par unvisits.loadDemands
positif dans le message de réponse. - Le véhicule livre l'envoi et la
vehicleLoads
du véhicule diminue du montant de laloadDemand
de l'envoi livré. Ce transfert est représenté par unvisits.loadDemands
négatif dans le message de réponse.
Le vehicleLoads
d'un véhicule ne peut pas dépasser son loadLimits
spécifié à tout moment de son parcours.
Exemple complet avec demandes et limites de charge
Voir un exemple de requête avec des demandes de charge et des limites
{ "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 } } } ] } }
L'exemple de requête contient plusieurs paramètres liés à la charge:
shipments[0]
a une demande de charge de 50weightKg
.shipments[1]
a une demande de charge de 10weightKg
.shipments[2]
a une demande de charge de 80weightKg
.vehicles[0]
est limité à 100weightKg
.
Afficher une réponse à la requête avec des demandes et des limites de charge
{ "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 } } }
Les contraintes de chargement ajoutées affectent l'ordre des visits
:
shipment[0]
est retiréshipment[1]
est retiréshipment[0]
est diffuséshipment[1]
est diffuséshipment[2]
est retiréshipment[2]
est diffusé
Cette commande indique que trois envois ne peuvent pas être effectués par le véhicule en même temps, car leur loadDemands
total dépasse la loadLimits
du véhicule.
Chaque entrée visits
inclut la modification de la charge du véhicule résultant de l'achèvement de la Visit
. Les valeurs de charge positives représentent le chargement de l'envoi, tandis que les valeurs négatives représentent le déchargement de l'envoi.
Chaque entrée transitions
inclut la charge totale du véhicule pendant la Transition
. transitions[2]
, par exemple, a une charge weightKg
de 60, représentant les charges combinées de shipment[0]
et shipment[1]
.
Les objets de métriques routes[0].metrics
et metrics.aggregatedRouteMetrics
incluent une propriété maxLoads
. La valeur du type weightKg
est 80, ce qui représente la partie du trajet du véhicule qui a transporté shipments[2]
jusqu'à son lieu de livraison.
Contraintes de limite de charge souple
Comme pour les périodes décrites dans la section Contraintes de période de ramassage et de livraison, les contraintes de limite de charge ont des variantes strictes et flexibles. La propriété maxLoad
du message LoadLimit
exprime une contrainte stricte: le véhicule ne doit jamais transporter de charge dépassant la valeur maxLoad
du type spécifié. Les propriétés softMaxLoad
et costPerUnitAboveSoftMax
expriment une contrainte souple, chaque unité dépassant softMaxLoad
entraînant un coût costPerUnitAboveSoftMax
.
Les contraintes de limite de charge souple ont plusieurs utilisations, par exemple:
- Équilibrer les expéditions sur un nombre de véhicules supérieur au nombre minimal nécessaire lorsque cela est rentable
- indiquer la préférence du conducteur concernant le nombre d'articles qu'il peut confortablement récupérer et livrer sur un trajet donné ;
- charger les véhicules en dessous de leur capacité physique maximale pour limiter l'usure et réduire les coûts de maintenance ;
Vous pouvez utiliser des contraintes de limite de charge stricte et flexible. Par exemple, une limite de charge stricte peut indiquer le poids maximal de la cargaison qu'un véhicule peut transporter en toute sécurité ou le nombre maximal d'articles pouvant être placés dans un véhicule à la fois, tandis qu'une limite de charge souple peut être le poids ou le nombre maximal d'articles qui mettrait à rude épreuve la capacité du conducteur à tout faire tenir dans le véhicule.