負荷の需要と制限

このガイドでは、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 は、2 つの車両の積載タイプのキーが一致する場合にのみ、割り当てられた車両の 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 の値だけ増加します。この転送は、レスポンス メッセージの正の 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 を超えているため、車両で 3 つの出荷を同時に完了できないことを示しています。

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 コストが発生します。

ソフトロード制限の制約には、次のような用途があります。

  • 費用対効果が高い場合は、必要な最小数よりも多くの車両に配送を分散する
  • 特定のルートで快適に乗車および配達できる アイテムの数をドライバーの好みを表す
  • 車両に積載可能な最大物理的容量を下回って摩耗を抑え、メンテナンス費用を削減

ハード負荷制限とソフト負荷制限は併用できます。たとえば、ハード積載制限は、車両が安全に運ぶことができる貨物の最大重量や 1 車両に一度に収納できるアイテムの最大数を表します。一方、ソフト積載制限は、ドライバーが車両にすべて収納する能力に負担がかかる最大重量またはアイテム数を表します。