Dalam posting ini, kita akan melihat bagaimana Flexport menggunakan matematika dan ilmu data untuk menyelesaikan masalah pengiriman dan mengirimkan barang tepat waktu dengan biaya serendah mungkin.Pertimbangkan skenario spekulatif: pengirim memiliki sepuluh keberangkatan dan satu penerbangan tujuan untuk pengiriman apa pun. Satu-satunya keputusan yang harus diambil adalah apakah akan menetapkan setiap pengiriman untuk penerbangan tunggal ini. Jika kami tidak menetapkan beban tertentu untuk penerbangan, anggaplah mungkin untuk memindahkannya dengan cara lain.Setiap pengiriman memiliki volume dan biaya, dan penerbangan dibatasi dalam volume. Anda mungkin menganggapnya sebagai masalah ransel yang disederhanakan. Jadi, ada 1024-1 = 1023 kemungkinan solusi (kami tidak akan mengirim pesawat kosong sama sekali).Kita dapat membuat spreadsheet untuk mendaftar seluruh solusi dan memilih yang paling menguntungkan. Tetapi bagaimana jika Anda memiliki sepuluh keberangkatan yang sama, tetapi dua penerbangan? Ini adalah 59.049 solusi hanya dalam 10 pengiriman.Forwarder besar memiliki lebih dari sepuluh keberangkatan dan, tentu saja, lebih dari dua penerbangan untuk dipilih, yang mengarah ke triliunan hingga triliunan solusi yang mungkin. Di antara mereka, hanya jutaan yang layak, yang berarti bahwa metode spreadsheet tradisional dapat menemukan setidaknya satu solusi yang layak. Tetapi kita tidak hanya membutuhkan solusi yang layak. Kami membutuhkan yang terbaik, solusi optimal. Bagaimana menemukan mereka di antara berbagai kemungkinan yang tak terhitung jumlahnya? Salah satu jawabannya adalah menggunakan pemrograman integer.Pemrograman integer adalah sub-bagian dari optimasi diskrit, bidang studi operasi yang terkait dengan meminimalkan beberapa fungsi tujuan yang tunduk pada kendala. Kami ingin meminimalkan total biaya, asalkan barang dikirim tepat waktu ke tempat yang tepat, ditumpuk dalam ULD (Unit Load Device - alat pengemasan barang). Kami mengupayakan solusi optimal, tetapi dalam praktiknya terkadang kami tidak dapat mencapainya. Dalam hal ini, kami puas dengan solusi yang baik atau dekat. Di sini kita membatasi diri pada model sederhana di mana solusi optimal dapat dicapai.Langkah pertama dalam memecahkan masalah ini adalah beralih ke literatur. Komunitas ilmiah telah berurusan dengan pengiriman barang selama bertahun-tahun. Kami menemukan beberapa karya yang sangat mengingatkan pada masalah kami. Kami mengambil banyak konsep dan notasi berikut dari karya-karya ini dan berterima kasih kepada penulis atas kontribusinya pada bidang ini.Kita mulai dengan mendefinisikan fungsi tujuan. Untuk meminimalkan biaya, kita perlu memahami konsep bobot standar. Singkatnya, berat standar adalah berat minimum yang disetujui oleh forwarder untuk bekerja, terlepas dari berapa berat sebenarnya yang ditawarkan. Kami memiliki berat total, berat standar, dan peluang untuk kelebihan berat dan, sebaliknya, kurang berat. Bobot standar dikalikan dengan underweight, jadi kita bisa mengabaikan underweight dan fokus pada faktor kelebihan beban dikalikan dengan kelebihan beban itu sendiri.Fungsi tujuannya adalah untuk meminimalkan biaya total, yang didefinisikan sebagai bobot total semua barang yang ditugaskan oleh ULD, dikalikan dengan faktor muatan. Misalnya, jika ULD1 memiliki 100 kilogram kemacetan dan tingkat kemacetan untuk ULD1 adalah $ 4 per kilogram, maka total biaya ULD 1 adalah $ 400. Jadi, kita perlu beberapa notasi untuk kelebihan berat badan dan nilainya.Biarkan saja βadalah bobot ULD j di atas standar dan β- faktor biaya untuk ULD yang sama. Kita perlu menghitung untuk semua . Jika , maka fungsi tujuan akan menjadi . Itu runtuh menjadi . Kami ingin meminimalkan nilai, jadi tujuan akhir kami:
Nilai untuk bukan nilai yang dihitung. Parameter ini diperoleh dari spreadsheet atau database. Tapi kita definisikan sebagai berat total kelebihan untuk ULD , yang dapat kita hitung sebagai total berat semua persediaan yang ditugaskan oleh ULD (menyatakannya ), dikurangi berat standar ULD ini. Bobot standar khusus untuk jenis ULD dan juga merupakan parameter. Biarkan saja βadalah bobot standar untuk ULD dalam kilogram. Kemudian jumlah bobot ekstra untuk ULD didefinisikan sebagai .Berat total ULD, tentu saja, tergantung pada bobot apa yang ditugaskan pada ULD dan beratnya. Oleh karena itu, kami memerlukan ekspresi untuk menghitungnya, termasuk detail yang disebutkan di atas.Ini hanyalah jumlah dari bobot yang ditetapkan oleh ULD. Bagaimana cara menunjukkan bahwa sejumlah barang telah ditugaskan ke ULD tertentu? Untuk melakukan ini, kita tidak perlu parameter, tetapi variabel solusi. Variabel keputusan adalah sesuatu yang dapat dikontrol oleh pemecah sambil meminimalkan fungsi objektif.Biarkan parameternya mewakili berat kotor beban dalam kilogram.Contohnya, berarti muatan 4 berbobot 500 kilogram.Biarkan saja βadalah variabel keputusan yang mengambil nilai 1, jika pengiriman menugaskan ULD dan sebaliknya. Jadi, ketika kita ingin menghitung semua pengiriman yang ditetapkan oleh ULD 3, kita dapat mengulang semua variabel , dimana . Jika kami memiliki 4 pengiriman, dan nomor pengiriman 1 dan 3 ditugaskan ke ULD 3, akan terlihat seperti ini:
Tetapi kita membutuhkan berat total, bukan kuantitas. Untuk mendapatkannya, Anda cukup mengalikan setiap variabel solusi dengan parameter bobot. Karena variabel keputusan mengambil nilai 0, jika tidak diberi bobot, maka bobot ini disetel ulang dan tidak termasuk dalam total. Misalkan bobot untuk kargo satu hingga empat adalah 10, 50, 25, dan 5. Maka total berat dalam ULD 3 adalah:
Mari kita tuliskan perhitungan total berat ini secara umum. Tentukan berat total ULD sebagai . Kemudian, dan . Kita dapat menciutkan ini menggunakan notasi penjumlahan dan . Karena kami ingin ini benar untuk semua kemungkinan, kami menggunakan tanda "untuk semua": . Ini memberi kami bentuk akhir dari batas berat total kami:
Berat ekstra
Sekarang kami memiliki berat total, kami dapat menerapkan formula kami untuk beban tambahan:
Misalnya, jika dan dan kemudian berat ekstra kilogram. Lipat gandakan dengan faktor biaya untuk mendapatkan hasil dalam dolar. Sepintas ini mungkin tampak cukup, tetapi bagaimana dengan kasus ketika berat total seluruh kargo untuk ULD tidak melebihi berat standar? Dalam hal ini, jika kita menggunakan rumus "sebagaimana adanya", maka kelebihan beban akan menjadi angka negatif. Misalnya, jika berat standar adalah 1650 kilogram dan berat total yang ditetapkan adalah 1.000 kilogram, maka kelebihan muatan = 1000β1650 = -650. Fungsi objektif mengalikan angka ini dengan faktor kelebihan beban dan kami mendapatkan angka negatif. Seolah pembawa membayar kami untuk pengiriman kurang dari biaya berat standar.Inilah yang benar-benar kita inginkan:.Ini sama dengan hanya menetapkan 0 untuk variabel, yang sesederhana membuat batasan., Jadi, kami mengimplementasikan fungsi max () dalam pemrograman matematika: a = max (b, c), yaitu, a> = b && a> = c. Mari kita lihat definisi kita.Fungsi objektif:: Rasio Kelebihan ULD : Kelebihan ULD ; UjP: Berat standar ULD jgi: Berat Pengiriman Bruto ixi,j: variabel keputusan; xi,j=1jika pengiriman iditugaskan oleh ULD j, 0jika tidak.yj: total berat semua pengiriman yang ditunjuk oleh ULD j; yj=βiβIgixi,jβjβJSetiap muatan harus terbang
Pada titik ini, kita bisa menulis ini dengan Python dan mengirimkannya ke pemecah. Jika kami melakukan ini, kami akan menemukan bahwa pemecah menetapkan nol pengiriman untuk penerbangan apa pun, dan kami dapat dengan cepat memahami alasannya: cara terbaik untuk meminimalkan fungsi tujuan adalah dengan tidak mengakumulasi biaya apa pun. Ini mengarah pada pembatasan berikut: setiap batch harus ditugaskan untuk beberapa ULD. Kami akan memperluas ini untuk setiap kargo yang harus ditugaskan ke satu dan hanya satu ULD, meskipun dalam kenyataannya kami dapat membagi kargo menjadi beberapa ULD dan bahkan beberapa penerbangan.Itu artinyaxi,jhanya bisa 1 untuk nilai tunggal $ j $. Misalnya, jika kami mempertimbangkan pengiriman 13, makax13,1+x13,2+x13,3+β¦+x13,J=1. Kami ingin menerapkan pembatasan ini untuk setiap pengiriman.i (yang kami tulis sebagai βiβI), dan kami dapat menutup tambahan menggunakan operator penjumlahan (β), jadi batasan terakhir kami adalah:
βjβJxi,j=1βiβI
Dengan batasan ini, pemecah akan benar-benar mulai menetapkan pengiriman untuk penerbangan, tetapi dia hanya akan mendistribusikan pengiriman antara semua penerbangan yang tersedia sampai bobot terpenuhi. Pemecah kemudian akan menempatkan setiap pengiriman yang tersisa dalam satu ULD dengan biaya tambahan paling sedikit. Tidak termasuk volume atau berat ULD ini. Jadi, pembatasan tambahan berikut adalah volume dan berat.Batasan Volume dan Berat
Mari kita putuskan UjMsebagai muatan maksimum dalam kilogram ULD jdan Ujsebagai volume maksimum dalam meter kubik ULD j. Mari kita putuskanvi, dan volume dalam meter kubik kargo i. Untuk membatasi model pada kapasitas beban maksimum dan volume maksimum, kami memiliki ketentuan:
yj<=UjMβjβJ
βiβIxi,jvi<=UjVβjβJ
Seorang veteran industri akan segera menyadari bahwa ini tidak benar. Mengapa? Karena pembatasan ini memperlakukan muatan seolah-olah dapat dituangkan, seperti air, ke volume berapa pun. Pada kenyataannya, muatannya kaku atau memiliki batasan lain, seperti susun. 10 meter kubik kargo tidak dapat dikemas dalam volume sewenang-wenang yang sama persis dengan 10 meter kubik. Untuk mengatasi kasus ini, Anda harus menyelesaikan masalah pengemasan dalam wadah. Kami memeriksa apakah volume tertentu akan cocok dengan yang lain, tetapi ini di luar cakupan artikel ini.Sekarang pemecah menetapkan ULD pengiriman, dengan menghormati berat dan volume maksimum sambil meminimalkan biaya total. Tetapi ada masalah lain: kami tidak mengatakan apa-apa tentang penunjukan barang dan ketaatan tanggal pengiriman. Sebenarnya, ada empat stempel waktu yang perlu Anda pertimbangkan saat menetapkan kiriman:Waktu kiriman sebenarnya siap untuk dikonsolidasikan dengan pengiriman lain di ULD dan memuat di penerbangan. Ayo gunakanQiβuntuk mewakili waktu pengiriman siap i.Waktu dimana barang harus dibongkar di tujuan didekonsolidasi dan tersedia untuk penerimaan, sebagai aturan, dari terminal kargo. Mari kita gunakan $ Q_i ^ + $ untuk mewakili batas waktu pengirimani.Waktu dimana semua kargo harus dikirim ke terminal kargo untuk memuat ke penerbangan. Ayo gunakanTjβuntuk merepresentasikan waktu kliping kargo ULD $ j $.Waktu kedatangan penerbangan: ini adalah waktu di mana kargo pada penerbangan tersedia di gudang tujuan. Ayo gunakanTj+ untuk mewakili waktu kedatangan penerbangan ULD jSumber dan Tujuan
Perkenalkan satu set lagi Ji, yang kami definisikan sebagai seperangkat penerbangan, yang sumber dan tujuannya bertepatan dengan keberangkatan dan penerimaan barang i. Dengan kata lain, jika keberangkatan 85 berasal dari Hong Kong dan tujuan di London, maka $ J_ {85} $ adalah himpunan semua ULD dengan keberangkatan dari Hong Kong dan tujuan di London.Sekarang bisa kita gunakanjβJi untuk mendapatkan kit ULD yang cocok dengan rute perdagangan pengiriman iatau bisa kita gunakan jβJiuntuk mendapatkan satu set ULD yang tidak cocok. Untuk melarang pengikatan kargo ke ULD, yang tidak sesuai dengan sumber dan tujuannya, kami hanya membatasixi,j=0untuk semua penerbangan tersebut. Pembatasan sepenuhnya dijelaskan sebagai berikut:
βjβJixi,j=0βiβI
Waktu pengiriman
Saat bekerja dengan cap waktu dalam pengoptimalan, akan lebih mudah untuk menyajikan momen yang diperlukan sebagai waktu Unix. Keuntungan dari pendekatan:- Menyimpan tanggal sebagai angka.
- Tidak perlu menangani zona waktu.
- Pemecah menggunakan perbandingan langsung lebih-kurang.
Penerbangan harus tiba sebelum waktu pengiriman:βjβJiTj+xi,j<=Qi+βiβIHarap dicatat bahwa, seperti halnya pembatasan di atas pada keberangkatan dan tujuan, kami telah mengindikasikan bahwa pembatasan ini hanya berlaku untuk ULD di set Jidimana Jiβadalah serangkaian ULD yang cocok dengan pengiriman dan penerimaan pengiriman i. Itu saja! Mari kita lihat keseluruhan model.Model lengkap
Di bawah batasan seperti itu, pemecah menetapkan barang-barang ULD dengan cara yang paling murah, dengan setiap kargo dikirim dari tempat keberangkatan yang tepat ke tujuan yang benar. Tentu saja, barang dikirim tepat waktu dan tanpa membebani barang dengan volume atau berat.Parameter
I: Satu set semua pengiriman. Satu pengiriman dikirimkaniJ: Satu set semua ULD. ULD individual adalah huruf kecilj.Ji: Satu set semua ULD yang cocok dengan pengirim dan penerima i.gi: Pengiriman berat kotor idalam kilogram.vi: Volume dalam meter kubik pengiriman icjE: Rasio Kelebihan ULD jdalam dolar AS per kilogramUjM: Kapasitas berat maksimum ULD jdalam kilogramUjV: Daya Surround Maksimum ULD jdalam meter kubikUjP: Berat standar ULD jdalam kilogramTjβ: Waktu pengiriman yang diizinkan ke terminal ULD j.Tj+: Waktu Kedatangan ULD j.Qiβ: Waktu Siap Pengiriman i. Qi+: Periode pengiriman i.Variabel keputusan dan fungsi tujuan:yj: Berat total ULD jyjE: Kelebihan ULD jdalam kilogram.xi,j: 1 jika mengirim iditugaskan oleh ULD j0 sebaliknya.Fungsi target
MinimizeβyjEcjE
Keterbatasan
yjβ- total berat pengiriman pada ULD $ j $: yj=βiβIgixi,jβjβJBerat ekstra jE adalah maks (0, yj-UjP):yjE>=yjβUjPβjβJyjE>=0βjβJSetiap pengiriman harus ditetapkan tepat ke 1 ULD: βjβJxi,j=1βiβI.ULDj tidak dapat melebihi berat maksimum: yj<=UjMβjβJULD jtidak dapat melebihi kapasitas maksimum: βiβIxi,jvi<=UjVβjβJLangkah selanjutnya
Artikel ini menjelaskan pemrograman matematika yang mendasari tujuan dari beban penerbangan. Tetapi menulis matematika saja tidak cukup. Langkah selanjutnya adalah mengimplementasikan program, mungkin dalam AML, seperti Pyomo, atau menggunakan API solvernya sendiri, misalnya, Python Gurobi API. Setelah itu, pengembang akan menulis kode untuk mentransfer parameter semua keberangkatan dan penerbangan yang tersedia. Kemudian instance model dikirim ke solver. Solver menetapkan nilai-nilai variabel keputusan secara optimal. Kemudian pengembang harus melakukan sesuatu dengan nilai-nilai variabel keputusan.