Demandas y límites de carga

En esta guía, se describen loadDemands y loadLimits, y cómo se relacionan entre ellos entre sí.

Como se menciona en Restricciones de los períodos de retiro y entrega, el El mensaje OptimizeToursRequest (REST, gRPC) contiene una serie de propiedades que especifican restricciones para el problema que se optimiza. Varios Las propiedades de OptimizeToursRequest representan restricciones de carga.

Los vehículos y los envíos tienen propiedades físicas que se deben considerar al planificar una ruta.

  • Vehículos: La propiedad loadLimits especifica la carga máxima que que el vehículo puede manejar. Ver los mensajes de Vehicle (REST, gRPC) en la documentación de Google Cloud.
  • Envíos: La propiedad loadDemands especifica cuánta carga tiene un valor determinado. que el envío de datos consume. Ver los mensajes de Shipment (REST, gRPC) en la documentación de Google Cloud.

Juntas, estas dos restricciones permiten que el optimizador Asignar adecuadamente los envíos a los vehículos de la manera que mejor se adapte la capacidad de tu flota y las demandas de envío.

En el resto de este documento, se analizan loadLimits y loadDemands en detalle.

Límites y demandas de carga: tipos

Se expresa cada demanda de carga y las restricciones de límite en términos de un tipo.

Puedes proporcionar tu propio conjunto de tipos de carga, como en los siguientes ejemplos:

  • peso
  • Volumen
  • mediciones lineales
  • nombres de los artículos o equipos que se transportan

En esta guía, se usa weightKg como tipo de ejemplo.

Tanto Shipment.loadDemands como Vehicle.loadLimits usan los búferes de protocolo Tipo de map, con claves string que representan los tipos de carga

Los valores de Shipment.loadDemands usan el mensaje Load (REST, gRPC). El mensaje Load tiene una sola propiedad amount que representa cuánta capacidad para completar el envío en el tipo especificado.

Los valores de Vehicle.loadLimits usan el mensaje LoadLimit (REST, gRPC). El mensaje LoadLimit tiene varias propiedades, como maxLoad que representa la capacidad de carga máxima del vehículo en el tipo especificado.

El loadDemands de un envío consume el loadLimits de su vehículo asignado solo si ambas tienen claves de tipo de carga coincidentes. Por ejemplo, un envío con loadDemands de:

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

requiere 50 unidades de carga en el tipo weightKg para que se realice el envío el proyecto se completó. Un vehículo con loadLimits de:

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

podría completar el envío, ya que el maxLoad del vehículo en la El tipo de weightKg es mayor o igual que la loadDemands del envío en el tipo weightKg. Sin embargo, un vehículo con loadLimits de lo siguiente:

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

Tiene de forma implícita una capacidad ilimitada de weightKg debido a la ausencia de una weightKg, por lo que el vehículo no está limitado por la configuración y la demanda de peso.

Transferencia de carga entre envíos y vehículos

Debido a que los vehículos recogen y entregan los envíos, la loadDemand transbordos entre el envío y el vehículo. Puedes consultar la las cargas del vehículo en el mensaje OptimizeToursResponse (REST, gRPC)routes.transitions para un vehículo determinado. La secuencia es tan sigue:

  1. La capacidad de carga requerida se define para el envío como un loadDemand.
  2. El vehículo asignado y el vehículo vehicleLoads aumenta en función del importe de loadDemand del envío. Esta el transbordo se representa con un visits.loadDemands positivo en la respuesta mensaje.
  3. El vehículo entrega el envío y disminuye su vehicleLoads por el importe de loadDemand del envío entregado. El transbordo está Se representa con un visits.loadDemands negativo en el mensaje de respuesta.

El valor de vehicleLoads de un vehículo no puede superar el loadLimits especificado en ningún momento en su ruta.

Ejemplo completo con demandas y límites de carga

Mira una solicitud de ejemplo con demandas de carga y límites

{
  "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 solicitud de ejemplo contiene varios parámetros relacionados con la carga:

  • shipments[0] tiene una demanda de carga de 50 weightKg.
  • shipments[1] tiene una demanda de carga de 10 weightKg.
  • shipments[2] tiene una demanda de carga de 80 weightKg.
  • vehicles[0] tiene un límite de carga de 100 weightKg.

Ver una respuesta a la solicitud con las demandas de carga y límites

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

Las restricciones de carga agregadas afectan el orden de visits:

  1. Se retiró shipment[0]
  2. Se retiró shipment[1]
  3. Se entregó shipment[0]
  4. Se entregó shipment[1]
  5. Se retiró shipment[2]
  6. Se entregó shipment[2]

Este pedido refleja que el vehículo no puede completar tres envíos en mismo tiempo porque su loadDemands total supera el loadLimits

Cada entrada de visits incluye el cambio en la carga del vehículo que resulta de la la finalización del Visit. Los valores de carga positivos representan la carga del envío los valores negativos representan la descarga del envío.

Cada entrada de transitions incluye la carga total del vehículo durante la Transition transitions[2], por ejemplo, tiene una carga de weightKg de 60. que representan las cargas combinadas de shipment[0] y shipment[1].

Los objetos de métricas routes[0].metrics y metrics.aggregatedRouteMetrics incluyen una propiedad maxLoads El valor del tipo weightKg es 80, lo que representa la parte de la ruta del vehículo que transportó shipments[2] a su y la ubicación de entrega.

Restricciones del límite de carga no definitiva

Al igual que con los períodos descritos en Período de retiro y entrega Restricciones, las restricciones del límite de carga tienen variantes duras y blandas. El La propiedad maxLoad del mensaje LoadLimit expresa una restricción estricta: el el vehículo nunca debe llevar una carga que supere el valor de maxLoad en el valor especificado el tipo de letra. Las propiedades softMaxLoad y costPerUnitAboveSoftMax expresan una por lo que cada unidad que excede softMaxLoad genera una Costo de costPerUnitAboveSoftMax.

Las restricciones del límite de carga reducida tienen varios usos, como los siguientes:

  • equilibrando los envíos entre más vehículos que la cantidad mínima necesaria cuando es rentable hacerlo
  • que expresa la preferencia del conductor por la cantidad de elementos que puede retiro y entrega en una ruta determinada
  • cargar vehículos por debajo de su capacidad física máxima para limitar el desgaste y reducir los costos de mantenimiento

Las restricciones de límites de carga estricta y flexible se pueden usar en conjunto. Por ejemplo, una restricción puede expresar el peso máximo de la carga que un vehículo puede transportar de forma segura o la cantidad máxima de artículos que entran en un vehículo a la vez, mientras que un límite de carga flexible puede ser el peso máximo o la cantidad de artículos que se podrían gravar la capacidad del conductor de colocar todo en el vehículo.