Richieste e limiti di carico

Questa guida descrive i criteri loadDemands e loadLimits e le loro correlazioni.

Come menzionato in Vincoli per le tempistiche di ritiro e consegna, il messaggio OptimizeToursRequest (REST, gRPC) contiene una serie di proprietà che specificano i vincoli sul problema da ottimizzare. Diverse proprietà OptimizeToursRequest rappresentano i vincoli di carico.

Veicoli e spedizioni hanno proprietà fisiche che devono essere prese in considerazione durante la pianificazione di un percorso.

  • Veicoli: la proprietà loadLimits specifica il carico massimo che il veicolo può sopportare. Consulta la documentazione del messaggio Vehicle (REST, gRPC).
  • Spedizioni: la proprietà loadDemands specifica il carico consumato da una determinata spedizione. Consulta la documentazione del messaggio Shipment (REST, gRPC).

Insieme, questi due vincoli consentono all'ottimizzatore di assegnare in modo appropriato le spedizioni ai veicoli nel modo che meglio corrisponde alla capacità della tua flotta e alle esigenze di spedizione.

Il resto del documento illustra in dettaglio loadLimits e loadDemands.

Richieste e limiti di carico: tipi

Esprimi ogni vincolo di carico e limitazione in termini di tipo.

Puoi fornire il tuo insieme di tipi di carico, come nei seguenti esempi:

  • weight
  • volume
  • misure lineari
  • nomi di articoli o attrezzature trasportati

Questa guida utilizza weightKg come tipo di esempio.

Sia Shipment.loadDemands sia Vehicle.loadLimits utilizzano il tipo map di buffer di protocollo, con chiavi string che rappresentano i tipi di carico.

I valori Shipment.loadDemands utilizzano il messaggio Load (REST, gRPC). Il messaggio Load ha una singola proprietà amount che rappresenta la capacità necessaria per completare la spedizione nel tipo specificato.

I valori Vehicle.loadLimits utilizzano il messaggio LoadLimit (REST, gRPC). Il messaggio LoadLimit ha diverse proprietà, in cui maxLoad rappresenta la capacità di carico massima del veicolo nel tipo specificato.

Il valore loadDemands di una spedizione utilizza il valore loadLimits del veicolo che è stato assegnato solo se i due hanno chiavi per il tipo di carico corrispondenti. Ad esempio, una spedizione con loadDemands di:

"loadDemands": {
  "weightKg": {
    "amount": 50
  }
}

richiede 50 unità di carico nel tipo weightKg per il completamento della spedizione. Un veicolo con loadLimits di:

"loadLimits": {
  "weightKg": {
    "maxLoad": 100
  }
}

potrebbe essere in grado di completare la spedizione, poiché il valore maxLoad del veicolo nel tipo weightKg è maggiore o uguale al valore loadDemands della spedizione nel tipo weightKg. Tuttavia, un veicolo con loadLimits di:

"loadLimits": {
  "equipmentRackStorage": {
    "maxLoad": 10
  }
}

ha implicitamente una capacità weightKg illimitata a causa dell'assenza di un limite di carico di weightKg, quindi il veicolo non è vincolato dalla domanda di peso della spedizione.

Trasferimento del carico tra spedizioni e veicoli

Poiché le spedizioni vengono ritirate e consegnate dai veicoli, i loadDemand vengono trasferiti tra la spedizione e il veicolo. Puoi visualizzare i carichi dei veicoli nella voce OptimizeToursResponse (REST, gRPC)routes.transitions del messaggio relativo a un determinato veicolo. La sequenza è la seguente:

  1. La capacità di carico richiesta è definita per la spedizione come loadDemand.
  2. La spedizione viene ritirata dal veicolo assegnato e il valore vehicleLoads del veicolo aumenta di un importo pari a loadDemand della spedizione. Questo trasferimento è rappresentato da un valore positivo visits.loadDemands nel messaggio di risposta.
  3. Il veicolo consegna la spedizione e il valore vehicleLoads del veicolo diminuisce dell'importo di loadDemand della spedizione consegnata. Questo trasferimento è rappresentato da un valore negativo visits.loadDemands nel messaggio di risposta.

Il valore vehicleLoads di un veicolo non può superare il valore loadLimits specificato in qualsiasi punto del percorso.

Un esempio completo con richieste e limiti di carico

Visualizza un esempio di richiesta con richieste e limiti di carico

{
  "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
          }
        }
      }
    ]
  }
}
    

La richiesta di esempio contiene diversi parametri relativi al carico:

  • shipments[0] ha una domanda di carico di 50 weightKg.
  • shipments[1] ha una domanda di carico del 10 weightKg.
  • shipments[2] ha una domanda di carico di 80 weightKg.
  • vehicles[0] ha un limite di carico di 100 weightKg.

Visualizza una risposta alla richiesta con richieste e limiti di carico

{
  "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
    }
  }
}
    

I vincoli di carico aggiunti influiscono sull'ordine di visits:

  1. shipment[0] è stato ritirato
  2. shipment[1] è stato ritirato
  3. shipment[0] consegnato
  4. shipment[1] consegnato
  5. shipment[2] è stato ritirato
  6. shipment[2] consegnato

Questo ordine indica che il veicolo non può completare tre spedizioni contemporaneamente perché il loro totale di loadDemands supera i loadLimits del veicolo.

Ogni voce visits include la variazione del carico del veicolo risultante dal completamento dei Visit. I valori positivi rappresentano il carico della spedizione, mentre i valori negativi rappresentano il carico di spedizione.

Ogni voce transitions include il carico totale del veicolo durante il Transition. transitions[2], ad esempio, ha un carico weightKg di 60, che rappresenta i caricamenti combinati di shipment[0] e shipment[1].

Gli oggetti delle metriche routes[0].metrics e metrics.aggregatedRouteMetrics includono una proprietà maxLoads. Il valore per il tipo weightKg è 80, che rappresenta la parte del percorso del veicolo che ha trasportato shipments[2] alla località di consegna.

Vincoli dei limiti di caricamento flessibili

Come per le finestre di tempo descritte in Vincoli per le tempistiche di ritiro e consegna, i vincoli dei limiti di carico hanno varianti rigidi e flessibili. La proprietà maxLoad del messaggio LoadLimit esprime un vincolo rigido: il veicolo non deve mai sostenere un carico superiore al valore maxLoad nel tipo specificato. Le proprietà softMaxLoad e costPerUnitAboveSoftMax esprimono un vincolo non flessibile, con ogni unità superiore a softMaxLoad che viene addebitato un costo di costPerUnitAboveSoftMax.

I vincoli dei limiti di caricamento flessibili hanno diversi usi, ad esempio:

  • bilanciare le spedizioni su più veicoli rispetto al numero minimo necessario quando è conveniente farlo
  • esprimere la preferenza del conducente per il numero di articoli che possono ritirare e consegnare comodamente su un determinato percorso
  • caricare i veicoli al di sotto della loro capacità fisica massima per limitare l'usura e ridurre i costi di manutenzione

I vincoli relativi ai limiti di carico rigido e flessibili possono essere utilizzati insieme. Ad esempio, un limite di carico massimo potrebbe esprimere il peso massimo di un carico che un veicolo può trasportare in sicurezza o il numero massimo di articoli che possono essere inseriti in un veicolo contemporaneamente, mentre un limite di carico flessibile potrebbe essere il peso massimo o il numero di articoli che imposterebbero la capacità del conducente di montare tutto nel veicolo.