Ce guide décrit loadDemands
et loadLimits
, et décrit les relations qui les unissent.
Comme indiqué dans la section Contraintes liées aux périodes de retrait et de livraison, le message OptimizeToursRequest
(REST, gRPC) contient un certain nombre de propriétés qui spécifient des contraintes concernant le problème à optimiser. Plusieurs propriétés OptimizeToursRequest
représentent des contraintes de charge.
Les véhicules et les expéditions possèdent 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
précise la charge maximale que le véhicule peut supporter. Consultez la documentation du messageVehicle
(REST, gRPC). - Expéditions: la propriété
loadDemands
spécifie la charge associée à un envoi donné. Consultez la documentation du messageShipment
(REST, gRPC).
Ensemble, ces deux contraintes permettent à l'optimiseur d'affecter correctement les expéditions aux véhicules de la manière la plus adaptée en termes de capacité de flotte et de demande d'expédition.
Ce reste de ce document présente loadLimits
et loadDemands
en détail.
Demandes et limites de charge: types
Vous exprimez chaque contrainte de demande de charge et de limite en termes de type.
Vous pouvez fournir votre propre ensemble de types de chargement, comme dans les exemples suivants:
- weight
- volume
- mesures linéaires
- le nom des objets ou équipements en cours de transport ;
Ce guide utilise weightKg
comme exemple de type.
Shipment.loadDemands
et Vehicle.loadLimits
utilisent tous deux le type map
de Protocol Buffers, 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é nécessaire pour effectuer la livraison 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 livraison n'utilise le loadLimits
du véhicule qui lui a été attribué que si les deux types de clés de chargement correspondent. Par exemple, un envoi avec le paramètre loadDemands
de:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
nécessite 50 unités de chargement dans le type weightKg
pour que la livraison soit terminée. Un véhicule avec loadLimits
des valeurs suivantes:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
peuvent être en mesure de finaliser l'expédition, car la valeur maxLoad
du véhicule dans le type weightKg
est supérieure ou égale à la valeur loadDemands
du colis dans le type weightKg
. Toutefois, un véhicule avec loadLimits
des valeurs suivantes:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
a implicitement une capacité de weightKg
illimitée en raison de l'absence de limite de chargement weightKg
. Le véhicule n'est donc pas limité par le poids du colis.
Transfert de charge entre les colis et les véhicules
Lorsque les colis sont récupérés et livrés par des véhicules, le loadDemand
est transféré entre le colis et le véhicule. Vous pouvez afficher les chargements du véhicule dans l'entrée du message OptimizeToursResponse
(REST, gRPC)routes.transitions
pour un véhicule donné. La séquence est la suivante:
- La capacité de chargement requise est définie pour la livraison 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 une valeurvisits.loadDemands
positive dans le message de réponse. - Le véhicule est livré, et le
vehicleLoads
du véhicule diminue du montant de l'loadDemand
du colis livré. Ce transfert est représenté par unvisits.loadDemands
négatif dans le message de réponse.
La valeur vehicleLoads
d'un véhicule ne peut dépasser la valeur loadLimits
spécifiée à aucun moment sur son itinéraire.
Exemple complet avec les exigences et les limites de charge
Voir un exemple de requête avec des exigences et des limites de charge
{ "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 au chargement:
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]
a une limite de chargement de 100weightKg
.
Afficher une réponse à la requête avec les exigences et les 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 charge ajoutées affectent l'ordre des éléments visits
:
shipment[0]
a été récupéréshipment[1]
a été récupéréshipment[0]
livréshipment[1]
livréshipment[2]
a été récupéréshipment[2]
livré
Cette commande indique que le véhicule ne peut pas effectuer trois expéditions en même temps, car le loadDemands
total dépasse la valeur loadLimits
du véhicule.
Chaque entrée visits
inclut la modification de la charge du véhicule résultant de l'achèvement de Visit
. Les valeurs de chargement positives représentent le chargement du colis, tandis que les valeurs négatives représentent le déchargement du colis.
Chaque entrée transitions
inclut la charge totale du véhicule pendant le Transition
. transitions[2]
, par exemple, a une charge weightKg
de 60, ce qui représente 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 correspond à la partie de l'itinéraire du véhicule qui a transporté shipments[2]
jusqu'à son lieu de livraison.
Contraintes de limite de chargement partiel
Comme pour les périodes décrites dans la section Contraintes liées aux périodes de retrait et de livraison, les contraintes de limite de charge comportent des variantes strictes et souples. La propriété maxLoad
du message LoadLimit
exprime une contrainte stricte: le véhicule ne doit jamais comporter de charge dépassant la valeur maxLoad
du type spécifié. Les propriétés softMaxLoad
et costPerUnitAboveSoftMax
expriment une contrainte flexible, chaque unité dépassant softMaxLoad
entraînant un coût de costPerUnitAboveSoftMax
.
Les contraintes de limite de chargement partiel ont plusieurs utilisations, par exemple:
- d'équilibrer les expéditions sur un plus grand nombre de véhicules que le minimum nécessaire lorsqu'il est rentable de le faire.
- Exprimant la préférence du conducteur pour le nombre d'articles qu'il peut facilement récupérer et livrer sur un itinéraire donné
- charger des véhicules en dessous de leur capacité physique maximale afin de limiter l'usure et de réduire les coûts d'entretien ;
Les contraintes de limite de charge stricte et de limite de charge souple peuvent être utilisées ensemble. Par exemple, une limite de charge stricte peut exprimer le poids maximal de la charge qu'un véhicule peut transporter en toute sécurité ou le nombre maximal d'articles pouvant être intégrés dans un véhicule à la fois, tandis qu'une limite de charge souple peut correspondre au poids maximal ou au nombre d'articles qui imposeraient au conducteur la capacité d'embarquer tous les éléments dans le véhicule.