Żądania i limity obciążenia

Deweloperzy z Europejskiego Obszaru Gospodarczego (EOG)

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ą Vehiclewiadomości (REST, gRPC).
  • Przesyłki: właściwość loadDemands określa, ile miejsca zajmuje dana przesyłka. Zapoznaj się z dokumentacją Shipmentwiadomoś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 loadLimitsloadDemands.

Żą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 OptimizeToursResponsewiadomości (REST, gRPC)routes.transitions dla danego pojazdu. Kolejność jest następująca:

  1. Wymagana pojemność ładunkowa jest określana dla przesyłki jako loadDemand.
  2. Przesyłka jest odbierana przez przypisany do niej pojazd, a jego vehicleLoads wzrasta o wartość loadDemand przesyłki. Ten transfer jest oznaczony dodatnim visits.loadDemands w wiadomości z odpowiedzią.
  3. 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 50 weightKg.
  • shipments[1] ma zapotrzebowanie na moc wynoszące 10 weightKg.
  • shipments[2] ma zapotrzebowanie na moc o wartości 80 weightKg.
  • vehicles[0] ma limit obciążenia wynoszący 100 weightKg.

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:

  1. shipment[0] został odebrany
  2. shipment[1] został odebrany
  3. shipment[0] jest dostarczony
  4. shipment[1] jest dostarczony
  5. shipment[2] został odebrany
  6. shipment[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]shipment[1].

Obiekty wskaźników routes[0].metricsmetrics.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 softMaxLoadcostPerUnitAboveSoftMax 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.