W tym przewodniku opisujemy funkcje loadDemands
i loadLimits
oraz ich wzajemne powiązania.
Jak wspomniano w sekcji Ograniczenia dotyczące czasu odbioru i dostawy, wiadomość OptimizeToursRequest
(REST, gRPC) zawiera wiele właściwości, które określają ograniczenia problemu podlegającego optymalizacji. Kilka właściwości OptimizeToursRequest
reprezentuje ograniczenia obciążenia.
Pojazdy i przesyłki mają właściwości fizyczne, które należy wziąć pod uwagę podczas planowania trasy.
- Pojazdy: właściwość
loadLimits
określa maksymalne obciążenie, jakie może udźwignąć pojazd. Zapoznaj się z dokumentacją dotyczącą wiadomościVehicle
(REST, gRPC). - Przesyłki: właściwość
loadDemands
określa, ile zasobów wykorzystuje dana przesyłka. Zapoznaj się z dokumentacją dotyczącą wiadomościShipment
(REST, gRPC).
Te 2 ograniczenia umożliwiają optymalizatorowi odpowiednie przypisywanie przesyłek do pojazdów w sposób, który najlepiej pasuje do pojemności Twojej floty i wymagań dotyczących przesyłek.
W pozostałej części tego dokumentu szczegółowo omawiamy loadLimits
i loadDemands
.
Zapotrzebowania i limity obciążenia: typy
Każde obciążenie i ograniczenie wyraża się w formie typu.
Możesz podać własny zestaw typów wczytywania, np.:
- waga
- głośność
- pomiary liniowe
- nazwy przewożonych przedmiotów lub sprzętu;
W tym przewodniku jako przykładowy typ danych użyto typu weightKg
.
Zarówno Shipment.loadDemands
, jak i Vehicle.loadLimits
używają typu Protocol Buffers (map
) z kluczami string
, które reprezentują typy ładowania.
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 wymagane do zrealizowania dostawy danego typu.
Wartości Vehicle.loadLimits
używają komunikatu LoadLimit
(REST, gRPC). Wiadomość LoadLimit
ma kilka właściwości, a wartość maxLoad
reprezentuje maksymalną ładowność pojazdu dla określonego typu.
loadDemands
przesyłki zużywa loadLimits
przypisanego pojazdu tylko wtedy, gdy oba mają pasujące klucze typu ładunku. Na przykład przesyłka z:
loadDemands
"loadDemands": {
"weightKg": {
"amount": 50
}
}
wymaga 50 jednostek ładunku typu weightKg
, aby przesyłka mogła zostać zrealizowana. Pojazd z loadLimits
:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
Może zrealizować dostawę, ponieważ maxLoad
pojazdu typu weightKg
jest większa lub równa loadDemands
przesyłki typu weightKg
. Jednak pojazd z loadLimits
:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
ma nieograniczoną pojemność weightKg
ze względu na brak limitu ładunku weightKg
, więc pojazd nie jest ograniczony przez wymaganą wagę przesyłki.
Przenoszenie ładunku między przesyłkami i pojazdami
Podczas odbioru i dostawy przesyłek przez pojazdy loadDemand
przesyłane są między przesyłką a pojazdem. Załadowania pojazdu możesz zobaczyć w wiadomości OptimizeToursResponse
(REST,
gRPC)routes.transitions
dla danego pojazdu. Sekwencja jest następująca:
- Wymagana pojemność ładunku jest definiowana 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 reprezentowany przez positivevisits.loadDemands
w odpowiedzi na wiadomość. - 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 trasy przekraczać określonej wartości loadLimits
.
Pełny przykład z wymaganiami i ograniczeniami dotyczącymi obciążenia
Przykład żądania 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 obciążeniem:
shipments[0]
ma obciążenie 50weightKg
.shipments[1]
ma zapotrzebowanie na moc 10weightKg
.shipments[2]
ma obciążenie 80weightKg
.vehicles[0]
ma limit wczytywania wynoszący 100weightKg
.
wyświetlić odpowiedź na żądanie z wymaganiami dotyczącymi obciążenia i limitami;
{ "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ło odebraneshipment[1]
zostało odebrane- Zrealizowano usługę
shipment[0]
- Zrealizowano usługę
shipment[1]
shipment[2]
zostało odebrane- Zrealizowano usługę
shipment[2]
W tym zamówieniu 3 przesyłki nie mogą być zrealizowane przez pojazd w tym samym czasie, ponieważ ich łączna waga loadDemands
przekracza loadLimits
pojazdu.
Każdy wpis visits
zawiera zmianę ładunku pojazdu wynikającą z ukończenia Visit
. Wartości dodatnie oznaczają załadowanie przesyłki, a ujemne – jej rozładunek.
Każdy wpis transitions
zawiera łączne obciążenie pojazdu w trakcie Transition
. Na przykład strona transitions[2]
ma wskaźnik weightKg
o wartości 60, co odpowiada łącznemu wskaźnikowi shipment[0]
i shipment[1]
.
Obiekty danych routes[0].metrics
i metrics.aggregatedRouteMetrics
zawierają właściwość maxLoads
. Wartość typu weightKg
to 80, co oznacza część trasy pojazdu, która transportowała shipments[2]
do miejsca dostawy.
Ograniczenia dotyczące limitu wczytywania
Podobnie jak w przypadku okien czasowych opisanych w sekcji Ograniczenia dotyczące okien odbioru i dostawy, limity obciążenia mają warianty twarde i miękkie. 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
określają ograniczenie łagodne, przy czym każda jednostka przekraczająca wartość softMaxLoad
powoduje koszt costPerUnitAboveSoftMax
.
Ograniczenia o miękkim limicie obciążenia mają kilka zastosowań, takich jak:
- równoważenie przesyłek na większej liczbie pojazdów niż minimalna wymagana liczba, gdy jest to opłacalne;
- wyrażenie preferencji kierowcy dotyczących liczby elementów, które może wygodnie odebrać i dostarczyć na danej trasie;
- ładowanie pojazdów poniżej ich maksymalnej fizycznej pojemności, aby ograniczyć zużycie i obniżyć koszty konserwacji;
Ograniczenia twardego i miękkiego limitu obciążenia można stosować jednocześnie. Na przykład sztywny limit ładunku może określać maksymalną wagę ładunku, który pojazd może bezpiecznie przewieźć, lub maksymalną liczbę elementów, które mieszczą się w pojeździe w danym momencie. Z kolei miękki limit ładunku może określać maksymalną wagę lub liczbę elementów, które stwarzają problemy kierowcy w przypadku spakowania wszystkiego w pojeździe.