В этом руководстве описаны 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 ) для данного транспортного средства. Последовательность следующая:
- Требуемая грузоподъемность определяется для перевозки как
loadDemand
. - Отгрузка забирается назначенным ей транспортным средством, и
vehicleLoads
транспортного средства увеличивается на величинуloadDemand
отправления. Эта передача представлена положительными числамиvisits.loadDemands
в ответном сообщении. - Транспортное средство доставляет груз, а
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]
имеет требуемую нагрузку 50weightKg
. -
shipments[1]
требуют загрузки 10weightKg
. -
shipments[2]
требуют нагрузки 80weightKg
-
vehicles[0]
предельная нагрузка составляет 100weightKg
.
Посмотреть ответ на запрос с требованиями и лимитами нагрузки
{ "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
:
-
shipment[0]
забран -
shipment[1]
забран -
shipment[0]
доставлен -
shipment[1]
доставлен -
shipment[2]
забран -
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
.
Ограничения мягкого ограничения нагрузки имеют несколько применений, например:
- балансировка поставок по большему количеству транспортных средств, чем минимально необходимое количество, когда это экономически выгодно
- выражение предпочтений водителя относительно количества предметов, которые он может с комфортом забрать и доставить по данному маршруту.
- загрузка транспортных средств ниже их максимальной физической вместимости для ограничения износа и снижения затрат на техническое обслуживание.
Жесткие и мягкие ограничения предельной нагрузки можно использовать вместе. Например, жесткий предел нагрузки может выражать максимальный вес груза, который транспортное средство может безопасно перевозить, или максимальное количество предметов, которые могут поместиться в транспортное средство одновременно, тогда как мягкий предел нагрузки может представлять собой максимальный вес или количество предметов, которые будет облагаться налогом на способность водителя разместить все в автомобиле.