負載需求和限制

本指南將說明 loadDemandsloadLimits,以及它們之間的關係。

上車和送達時間限制所述,OptimizeToursRequest 訊息 (RESTgRPC) 包含多個屬性,可指定要最佳化的問題的限制。幾個 OptimizeToursRequest 屬性代表載入限制

車輛和貨物都有物理屬性,因此在規劃路線時必須考量這些屬性。

  • 車輛loadLimits 屬性會指定車輛可處理的最大負載。請參閱 Vehicle 訊息 (RESTgRPC) 的說明文件。
  • ShipmentsloadDemands 屬性會指定指定出貨項目會消耗多少負載。請參閱 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。例如,出貨項目的 loadDemands 為:

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

需要 weightKg 類型的 50 個負載單位,才能完成出貨作業。loadLimits 為:

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

可能可以完成出貨,因為車輛在 weightKg 類型中的 maxLoad 大於或等於出貨在 weightKg 類型中的 loadDemands。不過,如果車輛的 loadLimits 為:

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

由於沒有 weightKg 負載限制,因此車輛會隱含地擁有無限 weightKg 容量,因此不會受到貨物重量需求的限制。

貨物和車輛之間的負載轉移

當車輛取貨和送貨時,貨物會在貨物和車輛之間傳輸 loadDemand。您可以在特定車輛的 OptimizeToursResponse 訊息 (RESTgRPC) routes.transitions 項目中,查看車輛的負載。順序如下:

  1. 運送作業所需的負載容量會定義為 loadDemand
  2. 貨物會由指定的車輛取走,且車輛的 vehicleLoads 會增加貨物的 loadDemand 數量。這項轉移作業會在回應訊息中以 positive visits.loadDemands 表示。
  3. 車輛運送貨物,車輛的 vehicleLoads 會依據已運送貨物的 loadDemand 數量而減少。這項轉移作業會在回應訊息中以 negative 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].metricsmetrics.aggregatedRouteMetrics 包含 maxLoads 屬性。類型 weightKg 的值為 80,代表車輛路線中將 shipments[2] 運送至目的地的那一部分。

軟性負載限制

如同「上車和下車時間窗口限制條件」一節所述,載客限制條件有硬式和軟式變化版本。LoadLimit 訊息的 maxLoad 屬性會表達硬性限制:車輛不得載運超過指定類型 maxLoad 值的負載。屬性 softMaxLoadcostPerUnitAboveSoftMax 會表達軟性限制,每個超過 softMaxLoad 的單位都會產生 costPerUnitAboveSoftMax 費用。

軟負載限制有幾種用途,例如:

  • 在成本效益可接受的情況下,將貨物分配給比必要數量更多的車輛
  • 表達駕駛員在特定路線上可輕鬆接送的物品數量偏好設定
  • 將車輛載重量控制在其物理最大容量以下,以減少磨損並降低維護成本

您可以同時使用硬性和軟性負載限制限制。舉例來說,硬負載限制可能會表示車輛可安全載運的最大貨物重量,或一次可放入車輛的最大物品數量,而軟負載限制則可能是駕駛員可將所有物品放入車輛的最大重量或物品數量。