OptimizeToursRequest
menerapkan batasan di seluruh hal berikut:
- Pengiriman, yang memengaruhi cara pengiriman dilakukan
- Kendaraan, yang memengaruhi cara penghitungan rute kendaraan
- Secara global, memengaruhi kendaraan dan pengiriman.
Panduan ini berfokus pada batasan pengiriman yang penting: periode waktu.
Jendela waktu adalah jenis batasan yang Anda berikan di
OptimizeToursRequest
pesan (REST, gRPC) untuk menentukan
batas waktu untuk aktivitas pengiriman. Jenis kendala ini mempengaruhi
baik kapan dan bagaimana pengiriman dapat dilakukan serta penugasan kendaraan
untuk pengiriman. Dengan batasan ini, pengoptimal memberikan preferensi untuk
kendaraan yang paling dapat memenuhi
batasan waktu pengiriman.
Batasan pengiriman: periode waktu
Anda menentukan kapan pengambilan atau pengantaran dapat dilakukan di Shipment.VisitRequest
sebagai berikut:
- Gunakan properti
timeWindows
dalam pesan (REST, gRPC) - Tentukan waktu mulai dan berakhir dalam pesan
TimeWindow
(REST, gRPC).
Contoh permintaan dengan batasan jangka waktu
Contoh di sini menggambarkan tiga pengiriman yang berbeda, masing-masing dengan
periode pengiriman. Untuk mempermudah, contoh ini menetapkan periode waktu pada deliveries
saja, tetapi jangka waktu juga dapat diterapkan ke pengambilan. Beberapa periode waktu dapat
ditentukan, meskipun contoh ini hanya menggunakan satu per pengiriman VisitRequest
.
Lihat contoh permintaan dengan jangka waktu
{ "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", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T19:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T18:30:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "endTime": "2023-01-13T18:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0 } ] } }
Contoh respons dengan batasan jangka waktu
Dalam contoh respons, waktu mulai dan berakhir kendaraan adalah 17:35:50 dan
18:17:24. Waktu ini mencerminkan pengoptimal yang meminimalkan waktu
diwajibkan untuk mengoperasikan kendaraan yang ditentukan dalam permintaan sebagai costPerHour
saat
memenuhi semua batasan periode waktu. Menggunakan 17:35:50 sebagai waktu mulai
sehingga kendaraan tidak perlu menunggu di lokasi kunjungan sampai
waktu kunjungan dimulai. Ini muncul dalam respons sebagai nol waitDuration
masing-masing.
Lihat respons terhadap contoh permintaan dengan periode waktu
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:35:50Z", "vehicleEndTime": "2023-01-13T18:17:24Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:35:50Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T17:38:20Z", "detour": "150s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:40:50Z", "detour": "300s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T17:50:09Z", "detour": "0s" }, { "shipmentIndex": 1, "startTime": "2023-01-13T18:00:00Z", "detour": "796s" }, { "startTime": "2023-01-13T18:07:35Z", "detour": "1520s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:35:50Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:38:20Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:40:50Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T17:43:20Z" }, { "travelDuration": "341s", "travelDistanceMeters": 1312, "waitDuration": "0s", "totalDuration": "341s", "startTime": "2023-01-13T17:54:19Z" }, { "travelDuration": "205s", "travelDistanceMeters": 636, "waitDuration": "0s", "totalDuration": "205s", "startTime": "2023-01-13T18:04:10Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-13T18:11:45Z" } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "1294s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2494s", "travelDistanceMeters": 4595 }, "routeCosts": { "model.vehicles.cost_per_hour": 27.711111111111112, "model.vehicles.cost_per_kilometer": 45.95 }, "routeTotalCost": 73.661111111111111 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1294s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2494s", "travelDistanceMeters": 4595 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:35:50Z", "latestVehicleEndTime": "2023-01-13T18:17:24Z", "totalCost": 73.661111111111111, "costs": { "model.vehicles.cost_per_hour": 27.711111111111112, "model.vehicles.cost_per_kilometer": 45.95 } } }
Periode waktu telah memesan visits
kendaraan agar pengiriman dengan
periode paling awal dikirim
terlebih dahulu.
shipments[2]
dikirim pada pukul 17.50shipments[1]
akan dikirim pada pukul 18.00shipments[0]
dikirim pada pukul 18.07
Contoh permintaan menentukan batasan jangka waktu hard, yang memerlukan
pengiriman harus diselesaikan
dalam jangka waktu tersebut. Jika menyelesaikan
VisitRequests
dalam jangka waktu yang tidak memungkinkan atau
hemat biaya, pengoptimal melewatkan pengiriman. Jika pengiriman memiliki
penaltyCost
, pengoptimal menambahkannya ke biaya yang dilaporkan sebagai respons
metrics
. Jika tidak, properti skippedMandatoryShipmentCount
dari
OptimizeToursResponse
pesan (REST, gRPC) meningkat.
Jika Anda mengubah periode waktu dengan menggeser periode shipment[1]
beberapa jam
kemudian (hingga 21:00 dari 18:00), hasilnya akan berbeda seperti yang digambarkan di
contoh berikut.
Lihat contoh permintaan dengan jangka waktu yang tidak dapat puas
{ "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", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T19:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T21:00:00Z", "endTime": "2023-01-13T21:30:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "endTime": "2023-01-13T18:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0 } ] } }
Lihat respons terhadap contoh permintaan kedua dengan periode waktu, di mana pengiriman dilewati
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:37:49Z", "vehicleEndTime": "2023-01-13T18:09:49Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:37:49Z", "detour": "0s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:40:19Z", "detour": "150s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T17:49:38Z", "detour": "0s" }, { "startTime": "2023-01-13T18:00:00Z", "detour": "946s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:37:49Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:40:19Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T17:42:49Z" }, { "travelDuration": "372s", "travelDistanceMeters": 1348, "waitDuration": "0s", "totalDuration": "372s", "startTime": "2023-01-13T17:53:48Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-13T18:04:10Z" } ], "metrics": { "performedShipmentCount": 2, "travelDuration": "1120s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1920s", "travelDistanceMeters": 3995 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 39.95, "model.vehicles.cost_per_hour": 21.333333333333332 }, "routeTotalCost": 61.283333333333331 } ], "skippedShipments": [ { "index": 1 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 2, "travelDuration": "1120s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1920s", "travelDistanceMeters": 3995 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:37:49Z", "latestVehicleEndTime": "2023-01-13T18:09:49Z", "totalCost": 81.283333333333331, "costs": { "model.shipments.penalty_cost": 20, "model.vehicles.cost_per_hour": 21.333333333333332, "model.vehicles.cost_per_kilometer": 39.95 } } }
Dalam contoh ini, periode waktu berikutnya telah menyebabkan shipment[1]
dilewati,
karena waktu operasional kendaraan tambahan yang
diperlukan untuk menyelesaikan proses pengiriman
pengiriman dalam periode waktu yang ditentukan melebihi biaya penalti pengiriman.
Biaya penalti untuk shipment[1]
muncul di metrics.costs
, dan indeksnya
muncul di skippedShipments
.
Batasan periode waktu sementara
Seperti yang disebutkan secara singkat dalam Parameter Model Biaya, periode waktu dapat diterapkan sebagai batasan soft. Batasan lunak berbeda dengan batasan keras sebagai berikut:
- Batasan keras: Tidak dapat dilanggar, dan pengoptimal tidak menawarkan yang melanggar batasan, meskipun itu berarti melewatkan pengiriman.
- Batasan ringan: Dapat dilanggar, yang berarti pengoptimal dapat memberikan solusi yang melanggar batasan ringan. Namun, pengoptimal juga akan menerapkan biaya untuk pelanggaran apa pun. Anda menyediakan biaya ini properti tambahan dalam jangka waktu tertentu, biasanya berupa biaya per jam setiap jam sebelum atau setelah jangka waktu terjadinya aktivitas.
Periode waktu diperhalus dengan menggunakan softStartTime
atau softEndTime
, bukan
startTime
atau endTime
, dan dengan menyetel
costPerHourBeforeSoftStartTime
atau costPerHourAfterSoftEndTime
.
Gunakan batasan jangka waktu lunak jika pengangkutan atau pengantaran harus dilakukan dalam jangka waktu tertentu, tetapi pengambilan atau pengiriman dalam periode tersebut tidak mutlak diperlukan. Anda dapat menggunakan batasan periode waktu baik secara bersamaan maupun tidak secara bersamaan untuk mengekspresikan tujuan bisnis. Contoh:
- Periode sulit: Menunjukkan jam buka pelanggan, seperti dari 09.00 hingga 17.00.
- Periode waktu lunak: Menunjukkan jangka waktu untuk pengiriman atau pengambilan yang cocok dengan notifikasi yang dikirimkan kepada pelanggan, misalnya pukul 09.00 hingga 13.00.
Dalam contoh ini, pengiriman yang sebelumnya dilewati karena waktunya terlalu lama dimulai, maka batasan waktu mulainya akan diperhalus. Lainnya pengiriman memiliki jangka waktu waktu berakhir juga melunak.
Lihat contoh permintaan dengan waktu hard dan soft jendela
{ "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", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "softEndTime": "2023-01-13T19:00:00Z", "costPerHourAfterSoftEndTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "softStartTime": "2023-01-13T21:00:00Z", "endTime": "2023-01-13T21:30:00Z", "costPerHourBeforeSoftStartTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "softEndTime": "2023-01-13T18:00:00Z", "costPerHourAfterSoftEndTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0 } ] } }
Lihat respons terhadap contoh permintaan dengan periode waktu lunak
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:48:35Z", "vehicleEndTime": "2023-01-13T18:24:28Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:48:35Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T17:51:05Z", "detour": "150s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:53:35Z", "detour": "300s" }, { "startTime": "2023-01-13T18:00:00Z", "detour": "300s" }, { "shipmentIndex": 1, "startTime": "2023-01-13T18:07:42Z", "detour": "493s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T18:17:27Z", "detour": "873s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:48:35Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:51:05Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:53:35Z" }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-13T17:56:05Z" }, { "travelDuration": "212s", "travelDistanceMeters": 791, "waitDuration": "0s", "totalDuration": "212s", "startTime": "2023-01-13T18:04:10Z" }, { "travelDuration": "335s", "travelDistanceMeters": 1204, "waitDuration": "0s", "totalDuration": "335s", "startTime": "2023-01-13T18:11:52Z" }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-13T18:21:37Z" } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "953s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2153s", "travelDistanceMeters": 3455 }, "routeCosts": { "model.shipments.deliveries.time_windows.cost_per_hour_after_soft_end_time": 0.58166666666666667, "model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time": 5.7433333333333332, "model.vehicles.cost_per_hour": 23.922222222222221, "model.vehicles.cost_per_kilometer": 34.55 }, "routeTotalCost": 64.797222222222217 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "953s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2153s", "travelDistanceMeters": 3455 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:48:35Z", "latestVehicleEndTime": "2023-01-13T18:24:28Z", "totalCost": 64.797222222222217, "costs": { "model.vehicles.cost_per_kilometer": 34.55, "model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time": 5.7433333333333332, "model.shipments.deliveries.time_windows.cost_per_hour_after_soft_end_time": 0.58166666666666667, "model.vehicles.cost_per_hour": 23.922222222222221 } } }
Ketika contoh dengan hanya batasan periode waktu sulit dilewati sepenuhnya
shipment[1]
, yang memperhalus periode waktu pengiriman akan menyebabkannya dikirimkan
sebelum waktu mulai periode waktunya. Demikian pula, memperhalus waktu berakhir
pengiriman lain diizinkan untuk mengirimkan shipment[2]
setelah batas waktunya
berakhir.
Pada saat yang sama, biaya dan total pengiriman telah berubah:
totalCost
: menurun dari 81,283 menjadi 64,797- total pengiriman yang diselesaikan: dinaikkan dari 2 menjadi 3
Pengoptimal telah menemukan solusi yang lebih murah karena jangka waktu lebih longgar dibandingkan dengan contoh sebelumnya.
Terakhir, properti metrics.costs
juga menyertakan kunci baru untuk menunjukkan
biaya aktual yang dikeluarkan berdasarkan produk kendala dan panjang
saat periode pengiriman terlewat. Definisinya yaitu:
costPerHourBeforeSoftStartTime
dari 2.0 dan- waktu antara pengiriman sebenarnya dan awal periode waktu: 2,83583 jam
Hasil:
model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time
:
5.6716666666666669.
Metrik ini memungkinkan Anda melakukan analisis biaya
untuk melihat kelebihan dan kekurangan dari
dan {i>soft constraint, <i} yang dapat Anda gunakan untuk
lebih sesuai dengan aturan bisnis Anda. Dalam hal ini, total biaya adalah
kurang dari shipment[1].penalty_cost
20.0. Pengoptimal telah mengidentifikasi
pengiriman paket akan lebih hemat biaya dan lebih cepat dibandingkan
melewati pengiriman.