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