arithmetic_coding_in_fixed_bits.sf 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #!/usr/bin/ruby
  2. # Author: Trizen
  3. # Date: 12 July 2023
  4. # Edit: 06 February 2024
  5. # https://github.com/trizen
  6. # The Arithmetic Coding algorithm, implemented using native integers.
  7. # References:
  8. # Data Compression (Summer 2023) - Lecture 15 - Infinite Precision in Finite Bits
  9. # https://youtube.com/watch?v=EqKbT3QdtOI
  10. #
  11. # Basic arithmetic coder in C++
  12. # https://github.com/billbird/arith32
  13. define (
  14. BITS = 32, # can be modified
  15. MAX = (1 << BITS)-1,
  16. EOF_SYMBOL = 256,
  17. )
  18. func create_cfreq(freq) {
  19. var c_low = Hash()
  20. var c_high = Hash()
  21. var T = 0
  22. for i in (0 .. EOF_SYMBOL) {
  23. freq{i} \\ next
  24. c_low{i} = T
  25. T += freq{i}
  26. c_high{i} = T
  27. }
  28. return (c_low, c_high, T)
  29. }
  30. func encode (String str) {
  31. var bytes = str.bytes+[EOF_SYMBOL]
  32. var enc = FileHandle.new_buf(:raw)
  33. var freq = bytes.freq
  34. var(cf_low, cf_high, T) = create_cfreq(freq)
  35. if (T > MAX) {
  36. die ("Too few bits: #{T} > ", MAX)
  37. }
  38. var low = 0
  39. var high = MAX
  40. var uf_count = 0
  41. for c in (bytes) {
  42. var w = (high - low + 1)
  43. high = (low + idiv(w * cf_high{c}, T) - 1)&MAX
  44. low = (low + idiv(w * cf_low{c}, T))&MAX
  45. if (high > MAX) {
  46. die "high > MAX: #{high} > #{MAX}"
  47. }
  48. if (low >= high) { die "#{low} >= #{high}" }
  49. loop {
  50. if ((high>>(BITS-1)) == (low>>(BITS-1))) {
  51. var bit = high>>(BITS-1)
  52. enc << bit
  53. if (uf_count > 0) {
  54. enc << Str(1 - bit)*uf_count
  55. uf_count = 0
  56. }
  57. low <<= 1
  58. high <<= 1 |= 1
  59. }
  60. elsif ((((low>>(BITS-2))&0x1) == 1) && (((high>>(BITS-2))&0x1) == 0)) {
  61. high <<= 1 |= (1 << (BITS-1)) |= 1
  62. low <<= 1 &= ((1 << (BITS-1)) - 1)
  63. ++uf_count
  64. }
  65. else {
  66. break
  67. }
  68. low &= MAX
  69. high &= MAX
  70. }
  71. }
  72. enc.print(0)
  73. enc.print(1)
  74. while (enc.parent.len % 8 != 0) {
  75. enc.print(1)
  76. }
  77. return (enc.parent, freq)
  78. }
  79. func decode (bits, freq) {
  80. var fh = bits.open_r(:raw)
  81. var(cf_low, cf_high, T) = create_cfreq(freq)
  82. if (T > MAX) {
  83. die "Too large value: #{T} > #{MAX}"
  84. }
  85. var dec = FileHandle.new_buf(:raw)
  86. var low = 0
  87. var high = MAX
  88. var enc = Num(BITS.of { fh.getc \\ 1 }.join, 2)
  89. var table = []
  90. for i in (0..EOF_SYMBOL) {
  91. cf_low{i} \\ next
  92. for j in (cf_low{i} ..^ cf_high{i}) {
  93. table[j] = i
  94. }
  95. }
  96. loop {
  97. var w = (high - low + 1)
  98. var ss = idiv(T*(enc - low + 1) - 1, w)
  99. var i = table[ss] \\ break
  100. break if (i == EOF_SYMBOL)
  101. dec << i.chr
  102. high = (low + idiv(w * cf_high{i}, T) - 1)&MAX
  103. low = (low + idiv(w * cf_low{i}, T))&MAX
  104. if (high > MAX) {
  105. die "high > MAX: #{high} > #{MAX}"
  106. }
  107. if (low >= high) { die "#{low} >= #{high}" }
  108. loop {
  109. if ((high>>(BITS-1)) == (low>>(BITS-1))) {
  110. high <<= 1 |= 1
  111. low <<= 1
  112. enc <<= 1 |= (fh.getc \\ 1)
  113. }
  114. elsif ((((low>>(BITS-2))&0x1) == 1) && (((high>>(BITS-2))&0x1) == 0)) {
  115. high <<= 1 |= (1 << (BITS-1)) |= 1
  116. low <<= 1 &= ((1 << (BITS-1)) - 1)
  117. enc = ((enc>>(BITS-1))<<(BITS-1))|((enc&((1<<(BITS-2))-1))<<1)|(fh.getc \\ 1)
  118. }
  119. else {
  120. break
  121. }
  122. low &= MAX
  123. high &= MAX
  124. enc &= MAX
  125. }
  126. }
  127. return dec.parent
  128. }
  129. var str = "ABRACADABRA AND A VERY SAD SALAD"
  130. if (ARGV) {
  131. if (File(ARGV[0]).exists) {
  132. str = File(ARGV[0]).read(:raw)
  133. }
  134. else {
  135. str = ARGV[0]
  136. }
  137. }
  138. var (enc, freq) = encode(str)
  139. say enc
  140. say ("String length: ", str.len)
  141. say ("Encoded bytes length: ", length(enc)/8)
  142. say ("Ratio: ", (enc.len/8)/str.len * 100)
  143. var dec = decode(enc, freq)
  144. assert_eq(str.len, dec.len)
  145. assert_eq(dec, str)
  146. __END__
  147. 0100110110111110100000000100000111110000110110011111000010110011011001000101100011011101001110000000010001111111
  148. String length: 32
  149. Encoded bytes length: 14
  150. Ratio: 43.75