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

В этом руководстве описаны loadDemands и loadLimits и то, как они связаны друг с другом.

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

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

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

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

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

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