تحميل الطلبات والحدود

يوضّح هذا الدليل loadDemands وloadLimits وعلاقتها ببعضها.

كما هو موضّح في قيود فترة استلام وتسليم الطلبات، تحتوي رسالة OptimizeToursRequest (REST وgRPC) على عدد من السمات التي تحدّد القيود على المشكلة التي يتم تحسينها. تمثّل عدة سمات OptimizeToursRequest قيود الحمولة.

تمتلك المركبات والشحنات خصائص جسدية يجب أخذها في الاعتبار عند تخطيط مسار.

  • المركبات: تحدد السمة loadLimits الحد الأقصى للحمولة التي يمكن للمركبة التعامل معها. يمكنك الاطّلاع على مستندات (REST وgRPC) الخاصة برسالة Vehicle.
  • الشحنات: تحدّد السمة loadDemands مقدار الحمولة التي تستهلكها شحنة معيّنة. يمكنك الاطّلاع على مستندات (REST وgRPC) الخاصة برسالة Shipment.

معًا، يتيح هذان القيدان لأداة التحسين تحديد الشحنات للمركبات بشكلٍ مناسب بطريقة تتوافق على أفضل نحو مع طاقة أسطولك ومتطلبات الشحن.

تتناول بقية هذا المستند loadLimits وloadDemands بالتفصيل.

متطلبات الحمل والحدود القصوى: الأنواع

أنت تعبِّر عن كل قيد من قيود الطلب على التحميل والحدّ الأقصى من حيث النوع.

يمكنك تقديم مجموعتك الخاصة من أنواع التحميل، مثل الأمثلة التالية:

  • الوزن
  • الحجم
  • القياسات الخطية
  • أسماء السلع أو المعدّات التي يتم نقلها

يستخدم هذا الدليل weightKg كنوع من الأمثلة.

يستخدم كلّ من Shipment.loadDemands وVehicle.loadLimits نوع map حِزم بروتوكول، مع مفاتيح string التي تمثّل أنواع الحمولة.

تستخدِم قيم Shipment.loadDemands رسالة Load (REST وgRPC). تحتوي الرسالة Load على سمة amount واحدة تمثّل السعة المطلوبة لإنجاز الشحنة بالنوع المحدّد.

تستخدم قيم Vehicle.loadLimits رسالة LoadLimit (REST وgRPC). تحتوي رسالة LoadLimit على عدة خصائص، حيث تمثّل maxLoad الحد الأقصى لسعة الحمولة في المركبة من النوع المحدّد.

لا تستهلك loadDemands للشحنة loadLimits للمركبة المخصّصة لها إلا إذا كانت تمتلك كلتاهما مفاتيح مطابقة لنوع الحمولة. على سبيل المثال، شحنة تشمل loadDemands مما يلي:

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

تتطلّب 50 وحدة تحميل من النوع weightKg لإكمال الشحنة. مركبة بها loadLimits من:

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

قد يكون بإمكانه إكمال الشحنة، لأنّ maxLoad للمركبة في نوع weightKg أكبر من أو يساوي loadDemands للشحنة في نوع weightKg. في المقابل، إذا كانت هناك مركبة بها loadLimits درجة:

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

تكون سعة weightKg غير محدودة ضمنيًا بسبب عدم توفّر حدّ حمولة weightKg، لذلك لا تكون المركبة محدودة بوزن الطلب على الشحنة.

نقل الحمولة بين الشحنات والمركبات

أثناء استلام الشحنات وتسليمها بواسطة المركبات، يتم نقل loadDemand الشحنة بين الشحنة والمركبة. يمكنك الاطّلاع على حمولات المركبة في إدخال routes.transitions لرسالة OptimizeToursResponse (REST، gRPC) لمركبة معيّنة. التسلسل هو كما يلي:

  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] على weightKg‏ 60، وهو يمثّل عدد عمليات التحميل المجمّعة لكلّ من shipment[0] وshipment[1].

يتضمن كائنات المقاييس routes[0].metrics وmetrics.aggregatedRouteMetrics السمة maxLoads. قيمة النوع weightKg هي 80، ما يمثّل جزء مسار المركبة الذي نقل shipments[2] إلى موقع التسليم.

قيود حدود التحميل الأولي

كما هو الحال مع الفترات الزمنية الموضّحة في قيود مدة الاستلام والتسليم، تتضمّن قيود الحد الأقصى للحمولة خيارَين صارمَين واختيارَين مرنَين. تعبّر السمة maxLoad لرسالة LoadLimit عن قيد صارم: يجب ألا تحمل المركبة أبدًا حمولة تتجاوز القيمة maxLoad في النوع المحدّد. تُعبّر السمتَان softMaxLoad وcostPerUnitAboveSoftMax عن قيد غير صارم، حيث تُكلّف كل وحدة تتجاوز softMaxLoad تكلفة costPerUnitAboveSoftMax.

هناك عدة استخدامات لقيود الحدّ الأقصى للتحميل غير الحاسم، مثل:

  • موازنة الشحنات عبر مركبات أكثر من الحد الأدنى اللازم عندما يكون ذلك موفرًا من حيث التكلفة
  • مع التعبير عن تفضيل السائق لعدد العناصر التي يمكنه استلامها وتسليمها على مسار معين بشكل مريح
  • تحميل المركبات بحمولة أقل من الحد الأقصى لطاقتها المادية للحد من التآكل و خفض تكاليف الصيانة

يمكن استخدام قيود الحد الأقصى والحد الأدنى للتحميل معًا. على سبيل المثال، قد يشير الحدّ الأقصى للحمولة الثابتة إلى الحدّ الأقصى لوزن الحمولة التي يمكن للمركبة حملها بأمان أو الحدّ الأقصى لعدد السلع التي يمكن وضعها في المركبة في وقت واحد، في حين قد يشير الحدّ الأقصى للحمولة المتغير إلى الحدّ الأقصى للوزن أو عدد السلع التي قد تُصعِّب على السائق وضع كلّ شيء في المركبة.