W tym przewodniku opisujemy loadDemands
i loadLimits
oraz ich wzajemne powiązania.
Jak wspomnieliśmy w sekcji Ograniczenia dotyczące przedziału czasu odbioru i dostawy, komunikat
OptimizeToursRequest
(REST, gRPC) zawiera szereg właściwości, które określają ograniczenia optymalizowanego problemu. Kilka właściwości
OptimizeToursRequest
reprezentuje ograniczenia dotyczące obciążenia.
Pojazdy i przesyłki mają właściwości fizyczne, które należy uwzględnić podczas planowania trasy.
- Pojazdy: w przypadku pojazdów
loadLimits
określa maksymalne obciążenie, jakie może przewieźć pojazd. Zapoznaj się z dokumentacjąVehicle
wiadomości (REST, gRPC). - Przesyłki: właściwość
loadDemands
określa, ile miejsca zajmuje dana przesyłka. Zapoznaj się z dokumentacjąShipment
wiadomości (REST, gRPC).
Te 2 ograniczenia umożliwiają optymalizatorowi odpowiednie przypisywanie przesyłek do pojazdów w sposób, który najlepiej odpowiada pojemności floty i zapotrzebowaniu na przesyłki.
W dalszej części tego dokumentu szczegółowo omówimy loadLimits
i loadDemands
.
Żądania i limity dotyczące obciążenia: typy
Każde ograniczenie dotyczące zapotrzebowania na moc i limitu wyrażasz za pomocą typu.
Możesz podać własny zestaw typów obciążeń, np. w ten sposób:
- waga
- głośność
- pomiary liniowe,
- nazwy przewożonych przedmiotów lub sprzętu;
W tym przewodniku jako przykładu używamy typu weightKg
.
Zarówno Shipment.loadDemands
, jak i Vehicle.loadLimits
używają typu Protocol Buffers z kluczami string
, które reprezentują typy obciążenia.map
Wartości Shipment.loadDemands
używają komunikatu Load
(REST, gRPC).
Wiadomość Load
ma jedną właściwość amount
, która określa, ile miejsca jest potrzebne do zrealizowania przesyłki w określonym typie.
Wartości Vehicle.loadLimits
używają komunikatu LoadLimit
(REST, gRPC). Wiadomość LoadLimit
ma kilka właściwości, a maxLoad
reprezentuje maksymalną ładowność pojazdu w określonym typie.
loadDemands
przesyłki wykorzystuje loadLimits
przypisanego do niej pojazdu tylko wtedy, gdy mają one pasujące klucze typu ładunku. Na przykład przesyłka z loadDemands
:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
wymaga 50 jednostek załadunku typu weightKg
, aby dostawa została zrealizowana. Pojazd z loadLimits
:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
Może zrealizować dostawę, ponieważ maxLoad
pojazdu typu weightKg
jest większa lub równa loadDemands
dostawy typu weightKg
. Pojazd z loadLimits
:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
ma nieograniczoną weightKg
pojemność ze względu na brak weightKg
limitu obciążenia, więc pojazd nie jest ograniczony przez zapotrzebowanie na wagę przesyłki.
Przenoszenie ładunku między przesyłkami i pojazdami
Gdy przesyłki są odbierane i dostarczane przez pojazdy, informacje o przesyłceloadDemand
są przekazywane między przesyłką a pojazdem. Obciążenia pojazdu możesz zobaczyć we wpisie OptimizeToursResponse
wiadomości (REST, gRPC)routes.transitions
dla danego pojazdu. Kolejność jest następująca:
- Wymagana pojemność ładunkowa jest określana dla przesyłki jako
loadDemand
. - Przesyłka jest odbierana przez przypisany do niej pojazd, a jego
vehicleLoads
wzrasta o wartośćloadDemand
przesyłki. Ten transfer jest oznaczony dodatnimvisits.loadDemands
w wiadomości z odpowiedzią. - Pojazd dostarcza przesyłkę, a jego
vehicleLoads
zmniejsza się o wartośćloadDemand
dostarczonej przesyłki. To przeniesienie jest reprezentowane przez ujemną wartośćvisits.loadDemands
w wiadomości z odpowiedzią.
vehicleLoads
pojazdu nie może w żadnym momencie przekroczyć określonej loadLimits
na trasie.
Pełny przykład z wymaganiami dotyczącymi obciążenia i limitami
Zobacz przykładowe żądanie z wymaganiami dotyczącymi obciążenia i limitami
{ "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 } } } ] } }
Przykładowe żądanie zawiera kilka parametrów związanych z wczytywaniem:
shipments[0]
ma zapotrzebowanie na moc w wysokości 50weightKg
.shipments[1]
ma zapotrzebowanie na moc wynoszące 10weightKg
.shipments[2]
ma zapotrzebowanie na moc o wartości 80weightKg
.vehicles[0]
ma limit obciążenia wynoszący 100weightKg
.
Wyświetlanie odpowiedzi na żądanie z informacjami o zapotrzebowaniu na obciążenie i limitach
{ "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 } } }
Dodane ograniczenia obciążenia wpływają na kolejność visits
:
shipment[0]
został odebranyshipment[1]
został odebranyshipment[0]
jest dostarczonyshipment[1]
jest dostarczonyshipment[2]
został odebranyshipment[2]
jest dostarczony
To zamówienie pokazuje, że pojazd nie może zrealizować 3 dostaw jednocześnie, ponieważ ich łączna loadDemands
przekracza loadLimits
pojazdu.
Każda pozycja visits
zawiera zmianę obciążenia pojazdu wynikającą z ukończenia Visit
. Dodatnie wartości obciążenia oznaczają załadunek przesyłki, a ujemne – rozładunek.
Każdy wpis transitions
zawiera całkowite obciążenie pojazdu w trakcie Transition
. Na przykład w przypadku transitions[2]
wartość weightKg
wynosi 60, co oznacza łączną liczbę wczytań shipment[0]
i shipment[1]
.
Obiekty wskaźników routes[0].metrics
i metrics.aggregatedRouteMetrics
zawierają właściwość maxLoads
. Wartość typu weightKg
to 80, co oznacza część trasy pojazdu, którą shipments[2]
pokonał do miejsca dostawy.
Ograniczenia dotyczące limitu obciążenia
Podobnie jak w przypadku przedziałów czasowych opisanych w sekcji Ograniczenia dotyczące przedziału czasowego odbioru i dostawy, ograniczenia dotyczące limitu obciążenia mają warianty ścisłe i elastyczne. Właściwość maxLoad
wiadomości LoadLimit
wyraża twarde ograniczenie: pojazd nigdy nie może przewozić ładunku przekraczającego wartość maxLoad
w określonym typie. Właściwości softMaxLoad
i costPerUnitAboveSoftMax
wyrażają miękkie ograniczenie, przy czym każda jednostka przekraczająca softMaxLoad
wiąże się z kosztem costPerUnitAboveSoftMax
.
Ograniczenia dotyczące limitu łagodnego wczytywania mają kilka zastosowań, np.:
- równoważenie przesyłek w większej liczbie pojazdów niż minimalna liczba niezbędna, gdy jest to opłacalne;
- określanie preferencji kierowcy dotyczących liczby przesyłek, które może wygodnie odebrać i dostarczyć na danej trasie;
- ładowanie pojazdów poniżej maksymalnej pojemności fizycznej, aby ograniczyć zużycie i zmniejszyć koszty konserwacji;
Ograniczenia dotyczące limitu obciążenia twardego i miękkiego mogą być używane razem. Na przykład limit twardy może określać maksymalną wagę ładunku, jaką pojazd może bezpiecznie przewieźć, lub maksymalną liczbę przedmiotów, które zmieszczą się w pojeździe naraz, a limit miękki może określać maksymalną wagę lub liczbę przedmiotów, które utrudniłyby kierowcy zmieszczenie wszystkiego w pojeździe.