이 가이드에서는 loadDemands
와 loadLimits
가 어떻게 연관되어 있는지 설명합니다.
수령 및 배송 시간 창 제약 조건에서 언급했듯이 OptimizeToursRequest
메시지 (REST, gRPC)에는 최적화되는 문제에 관한 제약 조건을 지정하는 여러 속성이 포함되어 있습니다. 여러 OptimizeToursRequest
속성은 로드 제약 조건을 나타냅니다.
차량과 운송의 경우 경로를 계획할 때 고려해야 하는 물리적 속성이 있습니다.
- Vehicles:
loadLimits
속성은 차량이 처리할 수 있는 최대 부하를 지정합니다.Vehicle
메시지 (REST, gRPC) 문서를 참조하세요. - 배송:
loadDemands
속성은 특정 배송이 소비하는 부하를 지정합니다.Shipment
메시지 (REST, gRPC) 문서를 참조하세요.
이 두 가지 제약 조건을 사용하면 최적화 도구가 차량 용량 및 배송 수요에 가장 적합한 방식으로 차량에 배송을 적절하게 할당할 수 있습니다.
이 문서의 나머지 부분에서는 loadLimits
및 loadDemands
에 대해 자세히 설명합니다.
로드 수요 및 한도: 유형
각 로드 수요 및 제한 제약조건을 유형의 관점에서 표현합니다.
다음 예와 같이 고유한 로드 유형 집합을 제공할 수 있습니다.
- weight
- 볼륨
- 선형 측정
- 운송하는 물품 또는 장비의 이름
이 가이드에서는 weightKg
를 예시 유형으로 사용합니다.
Shipment.loadDemands
및 Vehicle.loadLimits
는 모두 로드 유형을 나타내는 string
키와 함께 프로토콜 버퍼 map
유형을 사용합니다.
Shipment.loadDemands
값은 Load
메시지 (REST, gRPC)를 사용합니다.
Load
메시지에는 지정된 유형의 배송을 완료하는 데 필요한 용량을 나타내는 단일 amount
속성이 있습니다.
Vehicle.loadLimits
값은 LoadLimit
메시지 (REST, gRPC)를 사용합니다. LoadLimit
메시지에는 여러 속성이 있으며 maxLoad
는 지정된 유형으로 차량의 최대 로드 용량을 나타냅니다.
배송의 loadDemands
는 두 차량에 일치하는 로드 유형 키가 있는 경우에만 할당된 차량의 loadLimits
를 사용합니다. 예를 들어 loadDemands
가 다음과 같은 배송의 경우는 다음과 같습니다.
"loadDemands": {
"weightKg": {
"amount": 50
}
}
배송을 완료하려면 weightKg
유형의 로드 단위가 50개 필요합니다. loadLimits
인 차량:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
weightKg
유형에서 차량의 maxLoad
이 weightKg
유형에 있는 배송의 loadDemands
보다 크거나 같으므로 배송을 완료할 수 있습니다. 그러나 loadLimits
가 다음과 같은 차량은 다음과 같습니다.
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
weightKg
로드 제한이 없으므로 암시적으로 weightKg
용량이 무제한이므로 차량이 배송 중량 수요의 제약을 받지 않습니다.
배송과 차량 간 부하 이전
차량이 화물을 수령하고 배송함에 따라 화물의 loadDemand
가 화물과 차량 간에 이전됩니다. 차량의 로드는 특정 차량의 OptimizeToursResponse
메시지 (REST, gRPC)routes.transitions
항목에서 확인할 수 있습니다. 순서는 다음과 같습니다.
- 배송에 필요한 적재 용량은
loadDemand
로 정의됩니다. - 할당된 차량이 배송을 수령하고 차량의
vehicleLoads
는 배송 상품의loadDemand
금액만큼 증가합니다. 이 전송은 응답 메시지에 양의visits.loadDemands
로 표시됩니다. - 차량이 화물을 배송하고 차량의
vehicleLoads
는 배송된 화물의loadDemand
양만큼 감소합니다. 이 전송은 응답 메시지에서 음의visits.loadDemands
로 표시됩니다.
차량의 vehicleLoads
은 경로의 어떤 지점에서도 지정된 loadLimits
를 초과할 수 없습니다.
부하 수요 및 한도가 포함된 전체 예시
부하 수요 및 한도가 있는 요청 예시 보기
{ "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 } } } ] } }
요청 예시에는 여러 로드 관련 매개변수가 포함되어 있습니다.
shipments[0]
의 로드 수요는 50weightKg
입니다.shipments[1]
의 로드 수요는 10weightKg
입니다.shipments[2]
의 로드 수요는 80weightKg
입니다.vehicles[0]
의 로드 한도는weightKg
100개입니다.
부하 수요 및 한도가 포함된 요청에 대한 응답 보기
{ "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 } } }
추가된 로드 제약조건은 visits
의 순서에 영향을 줍니다.
shipment[0]
픽업되었습니다shipment[1]
픽업되었습니다shipment[0]
배송됨shipment[1]
배송됨shipment[2]
픽업되었습니다shipment[2]
배송됨
이 주문은 차량의 총 loadDemands
가 차량의 loadLimits
를 초과하므로 3건의 배송을 동시에 완료할 수 없음을 반영합니다.
각 visits
항목에는 Visit
완료로 인한 차량 부하의 변경사항이 포함됩니다. 양의 부하 값은 배송 로드를 나타내고, 음수 값은 배송 중량을 나타냅니다.
각 transitions
항목에는 Transition
중의 총 차량 수하물이 포함됩니다. 예를 들어 transitions[2]
의 weightKg
로드는 60이며 이는 shipment[0]
와 shipment[1]
의 결합된 로드를 나타냅니다.
측정항목 객체 routes[0].metrics
및 metrics.aggregatedRouteMetrics
에는 maxLoads
속성이 포함됩니다. 유형 weightKg
의 값은 80이며 shipments[2]
를 배송 위치로 이동한 차량 경로의 일부를 나타냅니다.
소프트 로드 한도 제약조건
수령 및 배송 시간 창 제약조건에 설명된 기간과 마찬가지로 부하 제한 제약조건에는 하드 및 소프트 변형이 있습니다. LoadLimit
메시지의 maxLoad
속성은 엄격한 제약 조건을 표현합니다. 즉, 차량은 지정된 유형에서 maxLoad
값을 초과하는 부하를 운반해서는 안 됩니다. 속성 softMaxLoad
및 costPerUnitAboveSoftMax
는 유연한 제약조건을 표현하며, softMaxLoad
를 초과하는 모든 단위에서는 costPerUnitAboveSoftMax
비용이 발생합니다.
소프트 로드 제한 제약조건은 다음과 같이 여러 용도로 사용할 수 있습니다.
- 필요한 최소 수량보다 많은 차량 간에 배송비를 균형 있게 조정하는 것이 비용 효율적인 경우
- 특정 경로에서 편안하게 픽업 및 배송할 수 있는 물품의 수에 대한 기사 선호도를 표현
- 마모를 제한하고 유지보수 비용을 절감하기 위해 최대 물리적 용량 이하로 차량을 로드
하드 및 소프트 부하 제한 제약 조건을 함께 사용할 수 있습니다. 예를 들어 하드 적재 제한은 차량이 안전하게 운반할 수 있는 화물의 최대 중량 또는 한 번에 차량에 담을 수 있는 최대 화물 수를 나타낼 수 있는 반면, 소프트 적재 제한은 운전자가 차량에 담을 수 있는 물건을 수용하는 데 부과되는 최대 중량 또는 물건 수일 수 있습니다.