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