Dalam mencoba memahami hubungan antara Huffman Coding, Arithmetic Coding, dan Range Coding, saya mulai berpikir tentang kekurangan pengkodean Huffman terkait dengan masalah fraksional pengemasan bit .
Artinya, misalkan Anda memiliki 240 nilai yang mungkin untuk simbol, dan diperlukan untuk menyandikan ini menjadi bit, Anda akan terjebak dengan 8 bit per simbol, meskipun Anda tidak memerlukan "penuh" 8, karena 8 dapat mengekspresikan 256 nilai yang mungkin per simbol. Solusi untuk masalah ini adalah sesuatu yang saya lihat disebut sebagai "pengepakan bit fraksional", di mana Anda dapat "menggeser bit" dengan non-kekuatan dua menggunakan perkalian. Seperti halnya multiplikasi kekuatan-dua yang bergeser x * 2 == x << 1
dan x * 4 == x << 2
seterusnya untuk semua kekuatan dua, demikian pula Anda dapat "bergeser" dengan non-kekuatan-2 dengan mengalikannya, dan mengemasnya dalam simbol fraksional-bit-berukuran .
Masalahnya mirip dengan pengkodean Huffman: Anda berakhir dengan kode yang panjangnya harus non-fraksional, dan karenanya memiliki inefisiensi pengepakan ini. Namun, Anda tidak bisa hanya menggunakan solusi fracitonal-bit-packing, karena solusi ini mengasumsikan simbol berukuran tetap.
Pertanyaannya adalah, adakah makalah atau solusi untuk meningkatkan huffman coding dengan ide yang mirip dengan fraksional-bit-packing untuk mencapai sesuatu yang mirip dengan aritmatika coding? (atau hasil yang bertentangan).
Jawaban:
Mari kita lihat cara berpikir yang sedikit berbeda tentang pengkodean Huffman.
Misalkan Anda memiliki alfabet tiga simbol, A, B, dan C, dengan probabilitas 0,5, 0,25, dan 0,25. Karena probabilitasnya adalah semua kekuatan terbalik dari dua, ini memiliki kode Huffman yang optimal (yaitu identik dengan pengkodean aritmatika). Kami akan menggunakan kode kanonik 0, 10, 11 untuk contoh ini.
Misalkan negara kita adalah bilangan bulat besar, yang akan kita sebut . Anda dapat menganggap penyandian sebagai fungsi yang mengambil status saat ini, dan simbol untuk menyandikan, dan mengembalikan status baru:s
Jadi mari kita mulai dengan negara 11 (yang 1011 dalam biner), menyandikan simbol B. Negara baru adalah 46, yang 101110 dalam biner. Seperti yang Anda lihat, ini adalah keadaan "lama" dengan urutan 10 ditambahkan di akhir. Kami memiliki dasarnya "output" urutan bit 10.
Sejauh ini baik.
Sekarang pikirkan sejenak tentang bagaimana pengkodean aritmatika bekerja. Jika Anda meletakkan probabilitas di atas penyebut umum, simbol A sebenarnya mewakili rentang , simbol B mewakili rentang dan simbol C mewakili kisaran .[04,24) [24,34) [34,44)
Pada dasarnya apa yang kita lakukan di sini adalah mengalikan semuanya dengan penyebut yang sama. Bayangkan bahwa keadaan sebenarnya dalam basis 4. Pengkodean simbol B benar-benar mengeluarkan angka 2 di basis itu, dan pengkodean simbol C menghasilkan keluaran angka 3 di basis itu.
Namun, simbol A sedikit berbeda, karena bukan seluruh digit pada basis 4.
Sebagai gantinya, kita dapat menganggap alfabet sebagai himpunan simbol A_0, A_1, B, C, dengan probabilitas yang sama. Ini, sekali lagi, memiliki kode Huffman optimal 00, 01, 10, 11. Atau, sekali lagi, kita dapat memikirkan hal ini di basis 4. Untuk menyandikan simbol, kita cukup melakukan:
Jadi sekarang sudah jelas bagaimana cara menyandikan simbol B dan C, tetapi untuk menyandikan simbol A, kita punya pilihan. Manakah dari dan harus kita gunakan?A 1A0 A1
Sekarang inilah ide cerdas: kita mencuri satu bit informasi dari negara :s
i=smod2
dan kemudian .encode(s′,Ai)
Dengan menggunakan contoh kami sebelumnya, , kami menemukan bahwa dan , dan kemudian . Status baru adalah 10101 dalam bentuk biner.s=11 s′=5 i=1 encode(5,A1)=4×5+1=21
Sekarang ini tidak menghasilkan keluaran bit yang persis sama dengan pengkodean Huffman, tetapi menghasilkan keluaran yang memiliki panjang yang sama. Dan saya harap Anda dapat melihat bahwa ini juga dapat diuraikan secara unik. Untuk mendekode simbol, kita mengambil sisanya ketika dibagi dengan 4. Jika nilainya 2 atau 3, maka simbolnya masing-masing adalah B atau C. Jika 0 atau 1, maka simbolnya adalah A, dan kemudian kita dapat mengembalikan sedikit informasi dengan mengalikan status dengan 2 dan menambahkan 0 atau 1.
Yang menyenangkan tentang pendekatan ini adalah bahwa ia meluas secara alami ke pengkodean fraksional-bit, ketika pembilang dan / atau penyebut probabilitas tidak kekuatan dua. Misalkan kita memiliki dua simbol, A dan B, di mana probabilitas A adalah dan probabilitas B adalah . Kemudian kita dapat menyandikan simbol dengan:35 25
Untuk menyandikan simbol A, kita ambil dan , lalu .i=smod3encode(s′,Ai)s′=⌊s3⌋ i=smod3 encode(s′,Ai)
Ini setara dengan pengkodean aritmatika. Ini sebenarnya keluarga metode yang dikenal sebagai Sistem Angka Asimetris , dan dikembangkan selama beberapa tahun terakhir oleh Jarek Duda. Arti nama harus jelas: untuk menyandikan simbol dengan probabilitas , Anda secara konseptual mencuri digit basis-p dari negara, dan kemudian menambahkan digit basis-q. Asimetri berasal dari menafsirkan negara sebagai angka dalam dua basis yang berbeda.pq
Alasan mengapa itu adalah keluarga metode pengkodean adalah bahwa apa yang kami lihat di sini tidak praktis dengan sendirinya; diperlukan beberapa modifikasi untuk menghadapi kenyataan bahwa Anda mungkin tidak memiliki bilangan bulat presisi tak terbatas untuk memanipulasi variabel keadaan secara efisien, dan ada berbagai cara yang dapat Anda lakukan untuk mencapai hal ini. Pengkodean aritmatika, tentu saja, memiliki masalah serupa dengan ketepatan untuk kondisinya.
Varian praktis termasuk rANS ("r" berarti "rasio") dan tANS ("table-driven").
ANS memiliki beberapa keunggulan menarik dibandingkan pengkodean aritmatika, baik yang praktis maupun teoritis:
Saya tidak berpikir saya akan melakukan pengkodean aritmatika lagi.
sumber
Sebagai contoh sederhana, jika Anda memiliki tiga simbol dengan probabilitas 1/3 masing-masing, pengodean Huffman optimal Anda akan menggunakan tiga simbol 0, 10 dan 11 dengan rata-rata 5/3 bit.
Ada 243 simbol yang dibuat dengan menggabungkan 5 simbol asli, masing-masing dengan probabilitas 1/243. Yang jauh lebih dekat dengan 1/256. Pengodean Huffman yang optimal akan mengkodekan 13 dari kelompok-kelompok ini dalam 7 bit dan 230 kelompok dalam 8 bit, untuk rata-rata 7,9465 bit per grup atau 1,5893 bit per simbol asli, turun dari 1,6667 bit untuk pengkodean Huffman asli, dengan pengkodean hitung mengambil 1,5850 bit.
Jadi secara teori Anda hanya bisa menggabungkan dua simbol masing-masing menjadi satu simbol yang lebih besar, atau tiga simbol masing-masing menjadi satu simbol yang lebih besar, dan menggunakan kode Hufman untuk kombinasi.
sumber