Требования и ограничения по нагрузке

Разработчики Европейской экономической зоны (ЕЭЗ)

В этом руководстве описываются loadDemands и loadLimits , а также их взаимосвязь.

Как упоминалось в разделе «Ограничения времени забора и доставки» , сообщение OptimizeToursRequest ( REST , gRPC ) содержит ряд свойств, которые определяют ограничения для оптимизируемой задачи. Несколько свойств OptimizeToursRequest представляют собой ограничения нагрузки .

Транспортные средства и грузы имеют физические свойства, которые необходимо учитывать при планировании маршрута.

  • Транспортные средства : свойство loadLimits определяет максимальную нагрузку, которую может выдержать транспортное средство. См. документацию по сообщениям Vehicle ( REST , gRPC ).
  • Shipments : свойство loadDemands определяет объём загрузки, потребляемый конкретной отправкой. См. документацию по сообщениям Shipment ( REST , gRPC ).

В совокупности эти два ограничения позволяют оптимизатору правильно распределять грузы по транспортным средствам таким образом, чтобы они наилучшим образом соответствовали вместимости вашего автопарка и потребностям в грузоперевозках.

В оставшейся части документа подробно обсуждаются loadLimits и loadDemands .

Требования и ограничения нагрузки: типы

Каждое требование по нагрузке и ограничение предела выражается в терминах типа .

Вы можете предоставить свой собственный набор типов нагрузки, как в следующих примерах:

  • масса
  • объем
  • линейные измерения
  • названия перевозимых предметов или оборудования

В этом руководстве в качестве примера типа используется weightKg .

Как Shipment.loadDemands , так и Vehicle.loadLimits используют тип map Protocol Buffers со string ключами, которые представляют типы нагрузки.

Значения Shipment.loadDemands используют сообщение Load ( REST , gRPC ). Сообщение Load имеет единственное свойство amount , которое указывает объём груза, необходимый для завершения отгрузки указанного типа.

Значения Vehicle.loadLimits используют сообщение LoadLimit ( REST , gRPC ). Сообщение LoadLimit имеет несколько свойств, среди которых maxLoad представляет максимальную грузоподъёмность транспортного средства указанного типа.

Значение loadDemands для груза расходует loadLimits назначенного транспортного средства только в том случае, если у обоих транспортных средств совпадают ключи типа груза. Например, для груза с loadDemands :

"loadDemands": {
  "weightKg": {
    "amount": 50
  }
}

Для завершения перевозки требуется 50 единиц груза с типом weightKg . Транспортное средство с loadLimits :

"loadLimits": {
  "weightKg": {
    "maxLoad": 100
  }
}

Возможно , нам удастся завершить перевозку, поскольку maxLoad транспортного средства в типе weightKg больше или равна loadDemands в типе weightKg . Однако транспортное средство с loadLimits :

"loadLimits": {
  "equipmentRackStorage": {
    "maxLoad": 10
  }
}

неявно имеет неограниченную грузоподъемность weightKg из-за отсутствия ограничения по весу weightKg , поэтому транспортное средство не ограничено требуемым весом груза.

Перераспределение груза между партиями и транспортными средствами

По мере того, как грузы забираются и доставляются транспортными средствами, loadDemand груза переносится между грузом и транспортным средством. Загрузки транспортного средства можно увидеть в записи routes.transitions сообщения OptimizeToursResponse ( REST , gRPC ) для данного транспортного средства. Последовательность выглядит следующим образом:

  1. Требуемая грузоподъемность для отправки определяется как loadDemand .
  2. Груз забирается назначенным транспортным средством, и vehicleLoads транспортного средства увеличивается на величину loadDemand груза. Этот перенос отображается положительным значением visits.loadDemands в ответном сообщении.
  3. Транспортное средство доставляет груз, и его vehicleLoads уменьшается на величину loadDemand доставленного груза. Этот перенос отображается отрицательным значением visits.loadDemands в ответном сообщении.

vehicleLoads транспортного средства не может превышать указанные loadLimits ни в одной точке маршрута.

Полный пример с требованиями к нагрузке и ограничениями

Посмотрите пример запроса с требованиями к нагрузке и ограничениями

{
  "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
          }
        }
      }
    ]
  }
}
    

Пример запроса содержит несколько параметров, связанных с нагрузкой:

  • shipments[0] имеет потребность в загрузке 50 weightKg .
  • shipments[1] имеют требуемую загрузку 10 кг weightKg .
  • shipments[2] имеют требуемую массу груза 80 weightKg .
  • vehicles[0] предельная нагрузка составляет 100 weightKg .

Посмотрите ответ на запрос с требованиями и ограничениями по нагрузке.

{
  "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
    }
  }
}
    

Добавленные ограничения нагрузки влияют на порядок visits :

  1. shipment[0] забран
  2. shipment[1] забран
  3. shipment[0] доставлен
  4. shipment[1] доставлен
  5. shipment[2] забирается
  6. shipment[2] доставлен

Этот заказ отражает тот факт, что три поставки не могут быть выполнены транспортным средством одновременно, поскольку их общая loadDemands превышает loadLimits транспортного средства.

Каждая запись visits включает изменение загрузки транспортного средства в результате завершения Visit . Положительные значения загрузки соответствуют загрузке, отрицательные — разгрузке.

Каждая запись transitions включает общую загрузку транспортного средства во время Transition . Например, transitions[2] имеет нагрузку weightKg равную 60, что представляет собой объединенную загрузку shipment[0] и shipment[1] .

Объекты метрик routes[0].metrics и metrics.aggregatedRouteMetrics включают свойство maxLoads . Значение типа weightKg равно 80, что соответствует части маршрута транспортного средства, доставившего shipments[2] до места назначения.

Мягкие ограничения предела нагрузки

Как и временные окна, описанные в разделе «Ограничения временных окон забора и доставки» , ограничения по нагрузке бывают жёсткими и мягкими. Свойство maxLoad сообщения LoadLimit выражает жёсткое ограничение: транспортное средство ни при каких обстоятельствах не должно перевозить груз, превышающий значение maxLoad для указанного типа. Свойства softMaxLoad и costPerUnitAboveSoftMax выражают мягкое ограничение: каждая единица груза, превышающая softMaxLoad , влечёт за собой стоимость costPerUnitAboveSoftMax .

Ограничения по мягкой нагрузке имеют несколько применений, например:

  • балансировка поставок между большим количеством транспортных средств, чем минимально необходимое количество, когда это экономически эффективно
  • выражая предпочтения водителя относительно количества товаров, которые он может с комфортом забрать и доставить по заданному маршруту
  • загрузка транспортных средств ниже их максимальной физической грузоподъемности для ограничения износа и снижения затрат на техническое обслуживание

Жёсткие и мягкие ограничения по нагрузке могут использоваться совместно. Например, жёсткий предел нагрузки может выражать максимальный вес груза, который транспортное средство может безопасно перевозить, или максимальное количество предметов, которые могут поместиться в транспортное средство одновременно, в то время как мягкий предел нагрузки может представлять собой максимальный вес или количество предметов, которые могут оказаться слишком сложными для водителя, чтобы разместить всё в транспортном средстве.