במדריך הזה מתוארים loadDemands
ו-loadLimits
וההקשר ביניהם.
כפי שצוין במגבלות של חלון זמן איסוף ואספקה, ההודעה OptimizeToursRequest
(REST, gRPC) מכילה מספר מאפיינים שמציינים אילוצים בבעיה עם האופטימיזציה. כמה מאפייני OptimizeToursRequest
מייצגים אילוצים של עומס.
לכלי רכב ולמשלוחים יש מאפיינים פיזיים שצריך להביא בחשבון כשמתכננים מסלול.
- כלי רכב: המאפיין
loadLimits
מציין את העומס המקסימלי שהרכב יכול לטפל בו. אפשר לעיין במסמכי התיעוד של ההודעהVehicle
(REST, gRPC). - Shipments: המאפיין
loadDemands
מציין את עומס הנתונים שמשלוח מסוים צורך. עיינו במסמכי העזרה של ההודעהShipment
(REST, gRPC).
שני האילוצים האלה מאפשרים לכלי האופטימיזציה להקצות ביעילות משלוחים לכלי רכב באופן שיתאים בצורה הטובה ביותר לקיבולת הצי ולביקוש המשלוחים.
בהמשך המסמך נסביר בפירוט על loadLimits
ו-loadDemands
.
דרישות עומס ומגבלות: סוגים
כל אילוץ של דרישה ועומס מוגדר לפי סוג.
אתם יכולים לספק קבוצה משלכם של סוגי עומסי עבודה, כמו הדוגמאות הבאות:
- משקל
- עוצמת קול
- מדידות לינאריות
- שמות הפריטים או הציוד שנשלחים
במדריך הזה אנחנו משתמשים בweightKg
כסוג לדוגמה.
גם Shipment.loadDemands
וגם Vehicle.loadLimits
משתמשים בסוג map
של Protocol Buffers, עם מפתחות 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
של המשלוח. ההעברה הזו מיוצגת על ידיvisits.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
. לדוגמה, לעמוד 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
.
למגבלות של מגבלת עומס רכה יש כמה שימושים, למשל:
- איזון בין המשלוחים לבין מספר כלי הרכב, מעבר למספר המינימלי הנדרש, כשהדבר משתלם מבחינה כלכלית
- להביע את העדפת הנהג לגבי מספר הפריטים שהוא יכול לאסוף ולספק בנוחות במסלול נתון
- טעינת רכבים מתחת לקיבולת הפיזית המקסימלית שלהם כדי להגביל את הבלאי ולצמצם את עלויות התחזוקה
מגבלות על עומסים כבדים וקלים אפשר להשתמש יחד. לדוגמה, מגבלת עומס קשיח יכולה לבטא את המשקל המקסימלי של המטען שרכב יכול לשאת בצורה בטוחה או את המספר המקסימלי של פריטים שיתאימו לרכב בו-זמנית, ומגבלת טעינה קלה יכולה להיות המשקל המקסימלי או מספר הפריטים שעלולים להטיל מס על היכולת של הנהג להכניס את כל הפריטים ברכב.