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

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

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

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

  • Транспортные средства : свойство loadLimits определяет максимальную нагрузку, которую может выдержать транспортное средство. См. документацию по сообщениям Vehicle ( REST , gRPC ).
  • Shipments : Свойство loadDemands определяет, сколько нагрузки потребляет данная отправка. См. документацию Shipment message ( 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] имеют требуемую загрузку weightKg 80 кг.
  • 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 .

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

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

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