עומסים ומגבלות

במדריך הזה מתארים את 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 של רכב נתון. הרצף הוא כפי ככה:

  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.

למגבלות של מגבלת טעינה רכה יש כמה שימושים, כמו למשל:

  • איזון בין כמות גדולה של כלי רכב לבין המספר המינימלי הדרוש מתי משתלם לעשות זאת
  • הבעת העדפה של הנהג לגבי מספר הפריטים שאפשר לקנות בו בנוחות איסוף ומשלוח במסלול נתון
  • טעינת כלי רכב מתחת לקיבולת הפיזית המקסימלית שלהם כדי להגביל בלאי להפחית את עלויות התחזוקה

מגבלות על עומסים כבדים וקלים אפשר להשתמש יחד. לדוגמה, קשה מגבלת עומס יכולה לבטא את המשקל המקסימלי של המטען שרכב יכול לשאת בצורה בטוחה או את המספר המקסימלי של פריטים שיתאימו לרכב בו-זמנית, בזמן מגבלת עומס קלים עשויה להיות המשקל המקסימלי או מספר הפריטים שנגבים היכולת של הנהג להתאים את כל הפריטים ברכב.