負荷の需要と制限

このガイドでは、loadDemandsloadLimits とそれらの相互関係について説明します。

集荷と配達の時間帯の制約で説明したように、OptimizeToursRequest メッセージ(RESTgRPC)には、最適化される問題の制約を指定する多くのプロパティが含まれています。いくつかの OptimizeToursRequest プロパティは負荷制約を表します。

車両と荷物には物理的な特性があり、ルート計画の際に考慮する必要があります。

  • 車両: loadLimits プロパティには、車両が処理できる最大負荷を指定します。Vehicle メッセージ(RESTgRPC)のドキュメントをご覧ください。
  • Shipments: loadDemands プロパティは、特定の送信で消費される負荷の量を指定します。Shipment メッセージ(RESTgRPC)のドキュメントをご覧ください。

この 2 つの制約を組み合わせることで、オプティマイザーは車両の容量と配送需要に最も適した方法で配送を車両に適切に割り当てることができます。

このドキュメントの残りの部分では、loadLimitsloadDemands について詳しく説明します。

負荷需要と上限: タイプ

各負荷需要と上限制約は、タイプで表します。

次の例のように、独自の負荷タイプのセットを指定できます。

  • weight
  • 音量
  • 線形測定
  • 運搬する物品や機器の名前

このガイドでは、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 タイプの車両の maxLoadweightKg タイプの配送の loadDemands 以上であるため、配送を完了できる可能性があります。ただし、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] が配信済み

この注文は、3 件の配送の合計 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 の費用が発生します。

ソフト制限には、次のようないくつかの用途があります。

  • 費用対効果が高い場合は、必要な最小数よりも多くの車両に配送を分散する
  • 特定のルートで快適に集荷して配達できる商品の数に関するドライバーの希望を示す
  • 車両の物理的な最大積載量を下回る荷物を積み、摩耗を抑えてメンテナンス費用を削減する

ハード制限とソフト制限は併用できます。たとえば、厳格な積載制限は、車両が安全に運搬できる貨物の最大重量や、車両に一度に収納できるアイテムの最大数を表します。一方、柔軟な積載制限は、ドライバーが車内にすべて収納できる最大重量やアイテム数を表します。