加载需求和限制

本指南介绍了 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 表示车辆在指定类型的最大负载能力。

仅当分配的车辆的 loadLimits 具有匹配的加载类型键时,运单的 loadDemands 才会消耗两者。例如,loadDemands 为以下项的运单:

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

需要 50 个 weightKg 类型的加载单元才能完成装运。一辆loadLimits属于以下车型的车辆:

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

可能能够完成装运,因为车辆的 maxLoad(属于 weightKg 类型)大于或等于运单的 loadDemands(属于 weightKg 类型)。但是,一辆 loadLimits 属于以下内容的车辆:

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

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

加载货物和车辆之间的移交作业

当货物由车辆取走和送达时,货物的 loadDemand 会在货物和车辆之间转移。您可以在指定车辆的 OptimizeToursResponse 消息的 (RESTgRPC)routes.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 而导致的车辆负载变化。负载为正值表示装运负载,负值表示装运卸载。

Transition 期间,每个 transitions 条目都包含车辆总负载。例如,transitions[2]weightKg 负载为 60,表示 shipment[0]shipment[1] 的负载组合。

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

软负载限制限制条件

自提和送货时间范围限制中所述的时间范围一样,负载限制限制具有硬性变体和软性变体。LoadLimit 消息的 maxLoad 属性表示了一个硬性约束:车辆承载的负载不得超过指定类型的 maxLoad 值。softMaxLoadcostPerUnitAboveSoftMax 属性表示一种软约束,每个超过 softMaxLoad 的单位都会产生 costPerUnitAboveSoftMax 费用。

软负载限制限制条件有多种用途,例如:

  • 平衡车辆数量,超过最低数量要求的车辆(如果这样做具有成本效益)
  • 让司机对特定航线能舒适地取货和送餐的偏好程度
  • 将车辆装入低于其最大物理容量的车辆,以限制磨损并降低维护成本

硬负载限制和软负载限制可结合使用。例如,硬性载重限制可以表示车辆可安全携带的货物的最大重量或一次可装在一辆车中的最大物品数量,而软载重限制可以表示对驾驶员在装在车辆中的所有物品造成影响的最大重量或物品数量。