-
Notifications
You must be signed in to change notification settings - Fork 0
/
arithmetic_coding.sf
130 lines (98 loc) · 2.63 KB
/
arithmetic_coding.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/ruby
# Author: Daniel "Trizen" Șuteu
# License: GPLv3
# Date: 01 May 2015
# Website: https://github.com/trizen
#
## The arithmetic coding algorithm.
#
# See also:
# https://en.wikipedia.org/wiki/Arithmetic_coding#Arithmetic_coding_as_a_generalized_change_of_radix
func cumulative_freq(freq) {
var cf = Hash()
var total = 0
256.range.each { |b|
if (freq.contains(b)) {
cf{b} = total
total += freq{b}
}
}
return cf
}
func arithmethic_coding(bytes, radix) {
# The frequency characters
var freq = Hash()
bytes.each { |c| freq{c} := 0 ++ }
# The cumulative frequency table
var cf = cumulative_freq(freq)
# Limit and base
var lim = bytes.end
var base = lim+1
# Lower bound
var L = 0
# Product of all frequencies
var pf = 1
# Each term is multiplied by the product of the
# frequencies of all previously occurring symbols
base.range.each { |i|
var x = (cf{bytes[i]} * base**(lim - i))
L += x*pf
pf *= freq{bytes[i]}
}
# Upper bound
var U = L+pf
var pow = pf.log(radix).int
var enc = ((U-1) // radix**pow) #/
return (enc, pow, freq)
}
func arithmethic_decoding(enc, radix, pow, freq) {
# Multiply enc by 10^pow
enc *= radix**pow;
var base = 0
freq.each_value { |v| base += v }
# Create the cumulative frequency table
var cf = cumulative_freq(freq);
# Create the dictionary
var dict = Hash()
cf.each_kv { |k,v|
dict{v} = k
}
# Fill the gaps in the dictionary
var lchar = ''
base.range.each { |i|
if (dict.contains(i)) {
lchar = dict{i}
}
elsif (!lchar.is_empty) {
dict{i} = lchar
}
}
# Decode the input number
var decoded = []
(base-1).downto(0).each { |i|
var pow = base**i;
var div = (enc // pow) #/
var c = dict{div}
var fv = freq{c}
var cv = cf{c}
var rem = ((enc - pow*cv) // fv) #/
enc = rem
decoded << c
}
# Return the decoded output
return decoded
}
#
## Run some tests
#
const radix = 10 # can be any integer greater or equal with 2
%w(DABDDB DABDDBBDDBA ABBDDD ABRACADABRA CoMpReSSeD Sidef Trizen google TOBEORNOTTOBEORTOBEORNOT 象形字).each { |str|
var (enc, pow, freq) = arithmethic_coding(str.bytes, radix)
var dec = arithmethic_decoding(enc, radix, pow, freq).join_bytes('UTF-8')
say "Encoded: #{enc} * #{radix}^#{pow}";
say "Decoded: #{dec}";
if (str != dec) {
die "\tHowever that is incorrect!"
}
say '-'*80;
}