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 kilka 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
loadLimitsokreśla maksymalne obciążenie, jakie może przewieźć pojazd. Zapoznaj się z dokumentacjąVehiclewiadomościREST, gRPC). - Przesyłki: właściwość
loadDemandsokreśla, ile miejsca zajmuje dana przesyłka. Zapoznaj się z dokumentacjąShipmentwiadomościREST, 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 tych przykładach:
- 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 oba mają 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 w weightKg jest większa lub równa loadDemands dostawy w 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 OptimizeToursResponsewiadomoś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
vehicleLoadswzrasta o wartośćloadDemandprzesyłki. Ten transfer jest oznaczony dodatnimvisits.loadDemandsw wiadomości z odpowiedzią. - Pojazd dostarcza przesyłkę, a jego
vehicleLoadszmniejsza się o wartośćloadDemanddostarczonej przesyłki. To przeniesienie jest reprezentowane przez ujemną wartośćvisits.loadDemandsw wiadomości z odpowiedzią.
vehicleLoads pojazdu nie może w żadnym momencie przekroczyć określonego 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]dostarczonoshipment[1]dostarczonoshipment[2]został odebranyshipment[2]dostarczono
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 okresie 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.