يوضّح هذا الدليل loadDemands
وloadLimits
، وكيفية ارتباطهما ببعضهما.
كما هو موضّح في قيود الفترة الزمنية للاستلام والتسليم، تحتوي الرسالة
OptimizeToursRequest
(REST، gRPC) على عدد من الخصائص التي تحدّد القيود على المشكلة التي يتم تحسينها. تمثّل عدة سمات OptimizeToursRequest
قيود التحميل.
تتضمّن المركبات والشحنات خصائص مادية يجب أخذها في الاعتبار عند التخطيط لمسار.
- المركبات: تحدّد السمة
loadLimits
الحد الأقصى للحمولة التي يمكن أن تحملها المركبة. اطّلِع على مستنداتVehicle
(REST وgRPC). - الشحنات: تحدّد السمة
loadDemands
مقدار الحمولة التي تستهلكها شحنة معيّنة. اطّلِع على مستنداتShipment
(REST وgRPC).
تتيح هاتان القيودان لخدمة التحسين إمكانية تحديد المركبات المناسبة للشحنات بطريقة تتناسب مع سعة أسطولك ومتطلبات الشحن.
يناقش الجزء المتبقي من هذا المستند loadLimits
وloadDemands
بالتفصيل.
متطلبات التحميل والحدود: الأنواع
يتم التعبير عن كل طلب تحميل وقيود الحد الأقصى من خلال نوع.
يمكنك تقديم مجموعة خاصة بك من أنواع الأحمال، مثل الأمثلة التالية:
- الوزن
- الحجم
- القياسات الخطية
- أسماء السلع أو المعدّات التي يتم نقلها
يستخدم هذا الدليل weightKg
كنوع مثال.
يستخدم كل من Shipment.loadDemands
وVehicle.loadLimits
النوع Protocol Buffers
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
يمكنك الاطّلاع على حمولات المركبة في إدخال رسالة OptimizeToursResponse
(REST أو gRPC)routes.transitions
لمركبة معيّنة. التسلسل هو كما يلي:
- يتم تحديد سعة الحمولة المطلوبة للشحنة على أنّها
loadDemand
. - يتم استلام الشحنة بواسطة المركبة المخصّصة لها، ويزداد
vehicleLoads
الخاص بالمركبة بمقدارloadDemand
الخاص بالشحنة. يتم تمثيل عملية النقل هذه بالقيمة positivevisits.loadDemands
في رسالة الردّ. - توصّل المركبة الشحنة وينخفض
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]
طلب تحميل يبلغ 50weightKg
. - لدى "
shipments[1]
" طلب تحميل يبلغ 10weightKg
. - تبلغ حمولة
shipments[2]
المطلوبة 80weightKg
. - يبلغ الحدّ الأقصى لعدد مرات تحميل
vehicles[0]
100weightKg
.
الاطّلاع على ردّ على الطلب يتضمّن متطلبات التحميل وحدوده
{ "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
على النحو التالي:
- تم استلام الطلب من
shipment[0]
- تم استلام الطلب من
shipment[1]
- تم تسليم
shipment[0]
- تم تسليم
shipment[1]
- تم استلام الطلب من
shipment[2]
- تم تسليم
shipment[2]
يشير هذا الطلب إلى أنّه لا يمكن للسيارة إكمال ثلاث شحنات في الوقت نفسه لأنّ إجمالي loadDemands
يتجاوز loadLimits
في السيارة.
يتضمّن كل إدخال visits
التغيير في حمولة المركبة الناتج عن إكمال Visit
. تمثّل قيم الحمولة الموجبة تحميل الشحنة، بينما تمثّل القيم السالبة تفريغ الشحنة.
يتضمّن كل إدخال transitions
إجمالي حمولة المركبة خلال Transition
. على سبيل المثال، تبلغ قيمة weightKg
في transitions[2]
60،
وهي تمثّل الأحمال المجمّعة لكل من shipment[0]
وshipment[1]
.
يتضمّن عنصرَا المقاييس routes[0].metrics
وmetrics.aggregatedRouteMetrics
السمة maxLoads
. قيمة النوع weightKg
هي 80، ما يمثّل جزء مسار المركبة الذي تم فيه نقل shipments[2]
إلى موقع التسليم.
قيود الحدّ الأقصى للتحميل السلس
كما هو الحال مع الفترات الزمنية الموضّحة في قيود الفترة الزمنية للاستلام والتسليم، تتضمّن قيود الحدّ الأقصى للحِمل نوعَين: قيود صارمة وقيود مرنة. تعرض السمة maxLoad
للرسالة
LoadLimit
قيدًا صارمًا: يجب ألا تحمل المركبة حمولة تتجاوز قيمة maxLoad
في النوع المحدّد. تعرض السمتان softMaxLoad
وcostPerUnitAboveSoftMax
قيدًا مرنًا، حيث تتكبّد كل وحدة تتجاوز softMaxLoad
تكلفة costPerUnitAboveSoftMax
.
تتعدّد استخدامات قيود الحدّ الأقصى للتحميل الجزئي، مثل:
- موازنة الشحنات على عدد من المركبات أكبر من الحد الأدنى المطلوب عندما يكون ذلك فعّالاً من حيث التكلفة
- تعبّر هذه السمة عن تفضيل السائق لعدد الطلبات التي يمكنه استلامها وتسليمها بشكل مريح على مسار معيّن.
- تحميل المركبات بأقل من سعتها القصوى المادية للحد من التلف وتقليل تكاليف الصيانة
يمكن استخدام قيود الحدّ الأقصى الصارم والحدّ الأقصى المرن للتحميل معًا. على سبيل المثال، قد يعبّر حدّ التحميل الصارم عن الحد الأقصى لوزن الحمولة التي يمكن أن تحملها مركبة بأمان أو الحد الأقصى لعدد العناصر التي يمكن أن تتسع لها مركبة في المرة الواحدة، بينما قد يكون حدّ التحميل المرن هو الحد الأقصى لوزن أو عدد العناصر التي قد تؤثر في قدرة السائق على وضع كل شيء في المركبة.