加载需求和限制

欧洲经济区 (EEA) 开发者

本指南介绍了 loadDemandsloadLimits,以及它们之间的关系。

提货和送货时间窗口限制中所述,OptimizeToursRequest 消息(RESTgRPC)包含多个属性,用于指定正在优化的问题的限制。多个 OptimizeToursRequest 属性表示加载限制

车辆和货件具有在规划路线时必须考虑的物理属性。

  • 车辆loadLimits 属性用于指定车辆可承受的最大负载。请参阅 Vehicle 消息(RESTgRPC)的文档。
  • 货件loadDemands 属性用于指定给定货件消耗的负载量。请参阅 Shipment 消息(RESTgRPC)的文档。

这两个限制条件共同使优化器能够以最符合车队容量和货运需求的方式将货运任务适当分配给车辆。

本文档的其余部分将详细讨论 loadLimitsloadDemands

负载需求和限制:类型

您可以使用类型来表达每项负载需求和限制条件。

您可以提供自己的负载类型集,如以下示例所示:

  • 重量
  • 音量
  • 线性测量
  • 所运输物品或设备的名称

本指南以 weightKg 为例。

Shipment.loadDemandsVehicle.loadLimits 都使用 Protocol Buffers map 类型,其中包含表示负载类型的 string 键。

Shipment.loadDemands 值使用 Load 消息(RESTgRPC)。Load 消息具有一个 amount 属性,用于表示完成指定类型的货件所需的运力。

Vehicle.loadLimits 值使用 LoadLimit 消息(RESTgRPC)。LoadLimit 消息具有多个属性,其中 maxLoad 表示车辆在指定类型下的最大载重能力。

只有当货件的 loadDemands 与其分配的车辆的 loadLimits 具有匹配的装载类型键时,货件才会消耗车辆的 loadLimits。例如,loadDemands 为以下值的货件:

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

需要 50 个 weightKg 类型装载单位才能完成装运。loadLimits的车辆:

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

可能能够完成配送,因为weightKg类型车辆的maxLoad大于或等于weightKg类型货件的loadDemands。不过,如果车辆的 loadLimits 为:

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

由于没有 weightKg 载重限制,因此隐式具有无限weightKg 容量,因此车辆不受货件重量需求的限制。

货物和车辆之间的装载转移

当车辆取货和送货时,货件的 loadDemand 会在货件和车辆之间转移。您可以在特定车辆的 OptimizeToursResponse 消息(RESTgRPCroutes.transitions 条目中查看车辆的负载。顺序如下:

  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] 的负载为 60,表示 shipment[0]shipment[1] 的总负载。weightKg

指标对象 routes[0].metricsmetrics.aggregatedRouteMetrics 包含 maxLoads 属性。类型为 weightKg 的值为 80,表示车辆运输 shipments[2] 到送货地点的路线所占的比例。

软负载限制约束

提货和送货时间窗口限制中所述的时间窗口一样,载重限制也分为硬性限制和软性限制。LoadLimit 消息的 maxLoad 属性表示一种硬性限制:车辆的载荷绝不能超过指定类型中的 maxLoad 值。属性 softMaxLoadcostPerUnitAboveSoftMax 表示一种软约束,每超出 softMaxLoad 一个单位就会产生 costPerUnitAboveSoftMax 的费用。

软负载限制约束有多种用途,例如:

  • 在这样做具有成本效益时,将货物分配到比必要最少数量更多的车辆上
  • 表达司机对在特定路线上可以舒适地取件和送件的数量的偏好
  • 使车辆的装载量低于其最大物理容量,以限制磨损并降低维护成本

硬性和软性负载限制约束可以一起使用。例如,硬性载重限制可能表示车辆可以安全载运的最大货物重量,或者车辆一次最多可容纳的物品数量,而软性载重限制可能表示会给驾驶员将所有物品装入车辆的能力带来压力的最大重量或物品数量。