Demandas e limites de carga

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

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 devem ser consideradas ao planejar um trajeto.

  • Veículos: a propriedade loadLimits especifica a carga máxima que o o veículo pode lidar. Consulte as mensagens do Vehicle (REST, gRPC). na documentação do Google Cloud.
  • Remessas: a propriedade loadDemands especifica a quantidade de carga de um determinado consumo de dados. Consulte as mensagens do Shipment (REST, gRPC). na documentação do Google Cloud.

Juntas, essas duas restrições possibilitam que o otimizador atribuir remessas a veículos de maneira apropriada a capacidade da frota e as demandas de envio.

O restante deste documento discute loadLimits e loadDemands em detalhes.

Demandas e limites de carga: tipos

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

É possível fornecer seu próprio conjunto de tipos de carga, como os 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.

Tanto Shipment.loadDemands quanto Vehicle.loadLimits usam os buffers de protocolo. Tipo map, 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 da remessa vai consumir o loadLimits do veículo atribuído apenas se os dois têm chaves de tipo de carga correspondentes. Por exemplo, uma remessa com loadDemands de:

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

requer 50 unidades de carga no 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 de weightKg ilimitada de forma implícita devido à ausência de um Limite de carga de weightKg para que o veículo não seja limitado pelo frete demanda de peso.

Transferência de carga entre remessas e veículos

Conforme as remessas são retiradas e entregues por veículos, o O loadDemand é transferido entre a remessa e o veículo. Confira o do veículo nas mensagens OptimizeToursResponse (REST, gRPC)routes.transitions para um determinado veículo. A sequência é como da seguinte forma:

  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. Isso transferência é representada por visits.loadDemands positivo na resposta mensagem.
  3. O veículo entrega a remessa, e o vehicleLoads diminui pelo valor de loadDemand da remessa entregue. Esta transferência é representado por visits.loadDemands negativo na mensagem de resposta.

A vehicleLoads de um veículo não pode exceder a loadLimits especificada em nenhum momento em seu trajeto.

Um exemplo completo com demandas e limites de carga

Confira um exemplo de solicitação com demandas de carga e limites

{
  "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 carregamento de 80 weightKg.
  • vehicles[0] tem um limite de carregamento de 100 weightKg.

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

{
  "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] foi retirado
  6. shipment[2] foi entregue

Esse pedido reflete que três envios não podem ser concluídos pelo veículo em ao mesmo tempo, porque o total de loadDemands excede o valor do veículo loadLimits.

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, que representam os carregamentos combinados 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. A 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 dos motoristas pelo número de itens que eles conseguem buscar e entregar em um determinado trajeto
  • carregando 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.