Demandes et limites de charge

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 message Vehicle (REST, gRPC).
  • Expéditions: la propriété loadDemands spécifie la charge associée à un envoi donné. Consultez la documentation du message Shipment (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:

  1. La capacité de chargement requise est définie pour la livraison en tant que loadDemand.
  2. Le colis est récupéré par le véhicule qui lui est attribué, et le vehicleLoads du véhicule augmente du montant du loadDemand du colis. Ce transfert est représenté par une valeur visits.loadDemands positive dans le message de réponse.
  3. 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 un visits.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 50 weightKg.
  • shipments[1] a une demande de charge de 10 weightKg.
  • shipments[2] a une demande de charge de 80 weightKg.
  • vehicles[0] a une limite de chargement de 100 weightKg.

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:

  1. shipment[0] a été récupéré
  2. shipment[1] a été récupéré
  3. shipment[0] livré
  4. shipment[1] livré
  5. shipment[2] a été récupéré
  6. 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.