W tym przewodniku opisujemy atrybuty loadDemands
i loadLimits
oraz ich związek ze sobą.
Jak wspomnieliśmy w sekcji Ograniczenia przedziału czasu odbioru i dostawy, wiadomość OptimizeToursRequest
(REST, gRPC) zawiera szereg właściwości, które określają ograniczenia optymalizowanego problemu. Kilka właściwości OptimizeToursRequest
określa 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, które może obsłużyć pojazd. Zapoznaj się z dokumentacją wiadomościVehicle
(REST, gRPC). - Przesyłki: właściwość
loadDemands
określa ilość obciążenia pochłanianego przez daną przesyłkę. Zapoznaj się z dokumentacją wiadomościShipment
(REST, gRPC).
Dzięki połączeniu tych 2 ograniczeń optymalizator może odpowiednio przypisywać przesyłki do pojazdów w sposób najlepiej odpowiadający pojemności floty i zapotrzebowaniu w zakresie dostaw.
W pozostałej części tego dokumentu szczegółowo omówione są loadLimits
i loadDemands
.
Obciążenia i limity: typy
Każde zapotrzebowanie na obciążenie i ograniczenie ograniczenia podajesz w postaci typu.
Możesz podać własny zestaw typów wczytywania, np.:
- waga
- wolumin
- pomiary liniowe
- nazwy przewożonych przedmiotów lub sprzętu;
W tym przewodniku jako przykładowego typu użyto pola weightKg
.
Shipment.loadDemands
i Vehicle.loadLimits
używają typu Bufory protokołu map
, gdzie klucze string
reprezentują typy obciążenia.
Wartości Shipment.loadDemands
używają komunikatu Load
(REST, gRPC).
Wiadomość Load
ma 1 właściwość amount
, która określa, jaka pojemność jest wymagana do złożenia zamówienia w określonym typie.
Wartości Vehicle.loadLimits
używają komunikatu LoadLimit
(REST, gRPC). Komunikat LoadLimit
ma kilka właściwości, z których maxLoad
oznacza maksymalną pojemność pojazdu w danym typie.
loadDemands
przesyłki wykorzystuje dane loadLimits
przypisanego pojazdu tylko wtedy, gdy oba te elementy mają pasujące klucze typu obciążenia. Na przykład przesyłka z loadDemands
o wartości:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
wymaga 50 jednostek wczytywania typu weightKg
, aby można było zrealizować dostawę. Pojazd, w którym masz loadLimits
:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
może zrealizować dostawę, ponieważ wartość maxLoad
pojazdu weightKg
jest większa lub równa loadDemands
dostawy w typie weightKg
. Jednak pojazd, którego loadLimits
ma:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
domyślnie ma nieograniczoną pojemność wynoszącą weightKg
ze względu na brak limitu obciążenia wynoszącego weightKg
, więc pojazd nie jest ograniczony przez wagę przesyłki.
Przewóz ładunku między przesyłkami a pojazdami
Gdy przesyłki są odbierane i dostarczane przez pojazdy, loadDemand
przesyłki jest przenoszony między nią a pojazdem. Obciążenie pojazdu możesz zobaczyć we wpisie OptimizeToursResponse
(REST, gRPC)routes.transitions
dla danego pojazdu. Sekwencja wygląda tak:
- Wymagana nośność obciążenia jest określona dla przesyłki jako
loadDemand
. - Przesyłka zostanie odebrana przez przypisany do niego pojazd, a
vehicleLoads
pojazdu zwiększy się oloadDemand
. Przeniesienie jest oznaczone przez dodatnią wartośćvisits.loadDemands
w wiadomości z odpowiedzią. - Pojazd dostarczy przesyłkę, a kwota
vehicleLoads
pojazdu zmniejsza się o wartośćloadDemand
dostarczonej przesyłki. To przeniesienie jest reprezentowane przez ujemne wartościvisits.loadDemands
w wiadomości z odpowiedzią.
Wartość vehicleLoads
pojazdu nie może przekroczyć określonej wartości loadLimits
w żadnym punkcie trasy.
Pełny przykład obciążenia i limitów obciążenia
Zobacz przykładowe żądanie z wymaganiami i limitami obciążenia
{ "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 na poziomie 50weightKg
.shipments[1]
ma obciążenie na poziomie 10weightKg
.shipments[2]
ma obciążenie na poziomie 80weightKg
.vehicles[0]
ma limit wczytywania wynoszący 100weightKg
.
Wyświetl odpowiedź na żądanie z żądaniami 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ść elementów visits
:
- Odebrano:
shipment[0]
- Odebrano:
shipment[1]
- Dostarczono:
shipment[0]
- Dostarczono:
shipment[1]
- Odebrano:
shipment[2]
- Dostarczono:
shipment[2]
Z tego zamówienia wynika, że pojazd nie może zrealizować 3 przesyłek jednocześnie, ponieważ łączna loadDemands
przekracza loadLimits
.
Każdy wpis visits
obejmuje zmianę w obciążeniu pojazdu wynikającą z uzupełnienia danych Visit
. Wartości dodatnie reprezentują wczytanie przesyłki, a ujemne – wyłapywanie przesyłki.
Każda pozycja transitions
uwzględnia łączne obciążenie pojazdu w okresie Transition
. Na przykład transitions[2]
ma obciążenie weightKg
równe 60, co odpowiada łącznemu wczytywaniu stron shipment[0]
i shipment[1]
.
Obiekty wskaźników routes[0].metrics
i metrics.aggregatedRouteMetrics
zawierają właściwość maxLoads
. Wartość dla typu weightKg
wynosi 80, co oznacza część trasy pojazdu, która przetransportowała obiekt shipments[2]
do miejsca dostawy.
Ograniczenia nieblokującego wczytywania
Tak jak w przypadku przedziałów czasu opisanych w sekcji Ograniczenia dotyczące przedziału czasu odbioru i dostawy, ograniczenia dotyczące limitów obciążenia mają wersje sztywne i łagodne. Właściwość maxLoad
w komunikacie LoadLimit
określa sztywne ograniczenie: pojazd nie może nigdy przenosić ładunku przekraczającego wartość maxLoad
w podanym typie. Właściwości softMaxLoad
i costPerUnitAboveSoftMax
wskazują na łagodne ograniczenie, przy czym każda jednostka przekracza softMaxLoad
, a cena wynosi costPerUnitAboveSoftMax
.
Ograniczenia nieograniczonego obciążenia mają kilka zastosowań:
- równoważenie wysyłki większej liczby pojazdów niż niezbędna do uzyskania minimalnej liczby, jeśli jest to opłacalne
- Przez wskazanie kierowcy, który jako kierowcy może wygodnie odebrać i przewieźć dany przedmiot
- ładowania pojazdów do maksymalnej pojemności fizycznej, aby zmniejszyć zużycie i koszty konserwacji
Ograniczeń twardego i niezmiennego obciążenia można używać jednocześnie. Na przykład limit twardego może wskazywać maksymalną ciężar ładunku, który może bezpiecznie przewieźć pojazd, lub maksymalną liczbę przedmiotów, które zmieści się w pojeździe jednorazowo. Limit ładunku to maksymalna waga lub liczba przedmiotów, które zmieściłyby się w pojeździe.