Demandas e limites de carga

Este guia descreve loadDemands e loadLimits e como eles se relacionam.

Como mencionado em Restrições da janela de tempo de retirada e entrega, A mensagem OptimizeToursRequest (REST, gRPC) contém vários itens propriedades que especificam restrições no problema que está sendo otimizado. Várias As propriedades OptimizeToursRequest representam restrições de carga.

Veículos e remessas têm propriedades físicas que precisam ser consideradas ao planejar uma rota.

  • Veículos: a propriedade loadLimits especifica a carga máxima que o veículo pode processar. Consulte as mensagens do Vehicle (REST, gRPC). na documentação do Google Cloud.
  • Envios: a propriedade loadDemands especifica a carga que um determinado envio consome. Consulte a documentação da mensagem Shipment (REST, gRPC).

Juntas, essas duas restrições permitem que o otimizador atribua os envios aos veículos de maneira adequada, de acordo com a capacidade da frota e as demandas de envio.

O restante deste documento discute loadLimits e loadDemands em detalhes.

Limites e demandas de carga: tipos

Você expressa cada demanda de carregamento e restrição de limite em termos de um tipo.

Você pode fornecer seu próprio conjunto de tipos de carga, como nos exemplos a seguir:

  • peso
  • volume
  • medidas lineares
  • nomes de itens ou equipamentos que estão sendo transportados

Este guia usa weightKg como um tipo de exemplo.

Shipment.loadDemands e Vehicle.loadLimits usam o tipo map de buffers de protocolo, com chaves string que representam os tipos de carga.

Os valores Shipment.loadDemands usam a mensagem Load (REST, gRPC). A mensagem Load tem uma única propriedade amount que representa quanta capacidade é obrigatório para concluir o envio do tipo especificado.

Os valores Vehicle.loadLimits usam a mensagem LoadLimit (REST, gRPC). A mensagem LoadLimit tem várias propriedades, com maxLoad que representa a capacidade máxima de carga do veículo no tipo especificado.

O loadDemands de um envio consome o loadLimits do veículo atribuído apenas se os dois tiverem chaves de tipo de carga correspondentes. Por exemplo, uma remessa com loadDemands de:

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

requer 50 unidades de carga do tipo weightKg para que o envio seja concluído. Um veículo com loadLimits de:

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

pode concluir o envio, já que o maxLoad do veículo no O tipo de weightKg é maior ou igual ao loadDemands do envio em o tipo weightKg. No entanto, um veículo com loadLimits de:

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

tem capacidade ilimitada de weightKg devido à ausência de um limite de carga de weightKg. Assim, o veículo não é limitado pela demanda de peso do envio.

Transferência de carga entre remessas e veículos

À medida que os envios são retirados e entregues por veículos, o loadDemand do envio é transferido entre o envio e o veículo. É possível conferir do veículo nas mensagens OptimizeToursResponse (REST, gRPC)routes.transitions para um determinado veículo. A sequência é como segue:

  1. A capacidade de carga necessária é definida para a remessa como um loadDemand.
  2. A remessa é retirada pelo veículo atribuído a ele e pela O vehicleLoads aumenta de acordo com o valor de loadDemand da remessa. Essa transferência é representada por visits.loadDemands positivo na mensagem de resposta.
  3. O veículo entrega a remessa, e o vehicleLoads diminui pelo valor de loadDemand da remessa entregue. Esta baldeação é representado por visits.loadDemands negativo na mensagem de resposta.

O vehicleLoads de um veículo não pode exceder o loadLimits especificado em nenhum ponto da rota.

Um exemplo completo com demandas e limites de carga

Exemplo de solicitação com limites e demandas de carga

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

O exemplo de solicitação contém vários parâmetros relacionados à carga:

  • shipments[0] tem uma demanda de carregamento de 50 weightKg.
  • shipments[1] tem uma demanda de carregamento de 10 weightKg.
  • shipments[2] tem uma demanda de carga de 80 weightKg.
  • O vehicles[0] tem um limite de carga de 100 weightKg.

Ver uma resposta à solicitação com demandas e limites de carga

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

As restrições de carga adicionadas afetam a ordem de visits:

  1. shipment[0] foi retirado
  2. shipment[1] foi retirado
  3. shipment[0] foi entregue
  4. shipment[1] foi entregue
  5. shipment[2] é retirado
  6. shipment[2] foi entregue

Esse pedido reflete que três remessas não podem ser concluídas pelo veículo ao mesmo tempo porque o total de loadDemands delas excede a loadLimits do veículo.

Cada entrada de visits inclui a mudança na carga do veículo resultante da a conclusão da Visit. Valores de carga positivos representam o carregamento da remessa, enquanto valores negativos representam descarregamento de remessas.

Cada entrada de transitions inclui a carga total do veículo durante o Transition. transitions[2], por exemplo, tem uma carga weightKg de 60, representando as cargas combinadas de shipment[0] e shipment[1].

Os objetos de métricas routes[0].metrics e metrics.aggregatedRouteMetrics incluem uma propriedade maxLoads. O valor do tipo weightKg é 80, representando a parte do trajeto do veículo que transportou shipments[2] até seu local de entrega.

Restrições de limite de carga flexível

Assim como os períodos de tempo descritos em Período de retirada e entrega Restrições, as restrições de limite de carga têm variantes rígidas e flexíveis. O A propriedade maxLoad da mensagem LoadLimit expressa uma restrição rígida: a o veículo nunca deve carregar cargas que excedem o valor de maxLoad no não é válido. As propriedades softMaxLoad e costPerUnitAboveSoftMax expressam uma propriedade restrição, com cada unidade acima de softMaxLoad incorrendo em um Custo de costPerUnitAboveSoftMax.

As restrições de limite de carga flexível têm vários usos, como:

  • equilibrar as remessas em mais veículos do que o número mínimo necessário quando é econômico fazer isso
  • Expressar a preferência do motorista para o número de itens que ele pode coletar e entregar confortavelmente em um determinado trajeto
  • carregar veículos abaixo da capacidade física máxima para limitar o desgaste e reduzir os custos de manutenção

As restrições de limite de carga rígida e flexível podem ser usadas juntas. Por exemplo, uma dificuldade o limite de carga pode expressar o peso máximo da carga que um veículo pode transportar com segurança ou o número máximo de itens que cabem em um veículo ao mesmo tempo, enquanto um o limite de carga flexível pode ser o peso ou número máximo de itens que seriam impostos capacidade do motorista de encaixar tudo no veículo.