Richieste e limiti di carico

Sviluppatori dello Spazio economico europeo (SEE)

Questa guida descrive loadDemands e loadLimits e il loro rapporto reciproco.

Come indicato in Vincoli della finestra temporale di ritiro e consegna, il messaggio OptimizeToursRequest (REST, gRPC) contiene una serie di proprietà che specificano i vincoli del problema da ottimizzare. Diverse proprietà OptimizeToursRequest rappresentano i vincoli di caricamento.

Veicoli e spedizioni hanno proprietà fisiche che devono essere prese in considerazione quando si pianifica un percorso.

  • Veicoli: la proprietà loadLimits specifica il carico massimo che il veicolo può gestire. 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).

Questi due vincoli consentono all'ottimizzatore di assegnare in modo appropriato le spedizioni ai veicoli in modo da corrispondere al meglio alla capacità della flotta e alle richieste di spedizione.

Il resto di questo documento descrive in dettaglio loadLimits e loadDemands.

Richieste e limiti di carico: tipi

Esprimi ogni vincolo di domanda e limite di carico in termini di tipo.

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

  • peso
  • volume
  • misure lineari
  • nomi degli articoli o delle attrezzature trasportati

Questa guida utilizza weightKg come tipo di esempio.

Sia Shipment.loadDemands che Vehicle.loadLimits utilizzano il tipo map Protocol Buffers, 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à, con maxLoad che rappresenta la capacità di carico massima del veicolo nel tipo specificato.

Il loadDemands di una spedizione consuma il loadLimits del veicolo assegnato solo se i due hanno chiavi del tipo di carico corrispondenti. Ad esempio, una spedizione con loadDemands di:

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

richiede 50 unità di carico di 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 maxLoad del veicolo nel tipo weightKg è maggiore o uguale al loadDemands della spedizione nel tipo weightKg. Tuttavia, un veicolo con loadLimits di:

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

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

Trasferimento del carico tra spedizioni e veicoli

Poiché le spedizioni vengono ritirate e consegnate dai veicoli, il loadDemand della spedizione viene trasferito tra la spedizione e il veicolo. Puoi visualizzare i carichi del veicolo nella voce OptimizeToursResponse (REST, gRPC)routes.transitions per 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 vehicleLoads del veicolo aumenta della quantità di loadDemand della spedizione. Questo trasferimento è rappresentato da visits.loadDemands nel messaggio di risposta.
  3. Il veicolo consegna la spedizione e il vehicleLoads del veicolo diminuisce della quantità di loadDemand della spedizione consegnata. Questo trasferimento è rappresentato da visits.loadDemands nel messaggio di risposta.

La vehicleLoads di un veicolo non può superare la loadLimits specificata in nessun punto del percorso.

Un esempio completo con richieste e limiti di carico

Visualizza una richiesta di esempio 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 correlati al caricamento:

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

Visualizza una risposta alla richiesta con le richieste di carico e i limiti

{
  "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 aggiuntivi influiscono sull'ordine di visits:

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

Questo ordine indica che tre spedizioni non possono essere completate dal veicolo contemporaneamente perché il loro loadDemands totale supera il loadLimits del veicolo.

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

Ogni voce transitions include il carico totale del veicolo durante il periodo Transition. transitions[2], ad esempio, ha un carico di weightKg pari a 60, che rappresenta i carichi 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 sua destinazione di consegna.

Vincoli di limite di carico soft

Come per le finestre temporali descritte in Vincoli per la finestra temporale di ritiro e consegna, i vincoli di limite di carico hanno varianti rigide e flessibili. La proprietà maxLoad del messaggio LoadLimit esprime un vincolo rigido: il veicolo non deve mai trasportare un carico superiore al valore maxLoad nel tipo specificato. Le proprietà softMaxLoad e costPerUnitAboveSoftMax esprimono un vincolo flessibile, in cui ogni unità che supera softMaxLoad comporta un costo costPerUnitAboveSoftMax.

I vincoli del limite di carico flessibile hanno diversi utilizzi, ad esempio:

  • bilanciamento delle spedizioni su più veicoli rispetto al numero minimo necessario quando è conveniente farlo
  • esprimendo la preferenza del conducente per il numero di articoli che può comodamente ritirare e consegnare su un determinato percorso
  • carico dei veicoli al di sotto della loro capacità fisica massima per limitare l'usura e ridurre i costi di manutenzione

I vincoli di limite di carico rigido e flessibile possono essere utilizzati insieme. Ad esempio, un limite di carico rigido potrebbe esprimere il peso massimo del carico che un veicolo può trasportare in sicurezza o il numero massimo di articoli che possono essere caricati in un veicolo contemporaneamente, mentre un limite di carico flessibile potrebbe essere il peso o il numero massimo di articoli che metterebbero a dura prova la capacità del conducente di caricare tutto nel veicolo.