easy_encoding 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -1
- data/README.md +16 -1
- data/lib/easy_encoding.rb +1 -0
- data/lib/easy_encoding/base.rb +48 -0
- data/lib/easy_encoding/configuration.rb +2 -2
- data/lib/easy_encoding/huffman.rb +8 -27
- data/lib/easy_encoding/node.rb +6 -8
- data/lib/easy_encoding/shannon_fano.rb +66 -0
- data/lib/easy_encoding/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 657a415e4bace49a68960ffb9d60a5046f43f8dc
|
4
|
+
data.tar.gz: 82fb47f7af8a5c8a95b679a05cc6dbb433083410
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2bc4d087b8f8a135e45a053db2fb34ae9c6a6f0fba234cef3d10980f5d4945aa1cfa0f1ff3585b832ac09f064965101b10d9d4bae4d904bccf26a3c5eecbcd7
|
7
|
+
data.tar.gz: 3a85acd7d59eba8b3428e4b6ae0d61870c203f363992b69f3e16226e47b415958012178279ca1e7a79878e2c9f9aae1bee4ba8d73d43f355a29f262af10cb7c4
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
AllCops:
|
2
2
|
Include:
|
3
3
|
- !ruby/regexp /\.rb$/
|
4
|
+
Exclude:
|
5
|
+
- 'spec/*'
|
4
6
|
Documentation:
|
5
7
|
Enabled: false
|
6
8
|
Style/FrozenStringLiteralComment:
|
@@ -10,4 +12,6 @@ Style/Semicolon:
|
|
10
12
|
Metrics/LineLength:
|
11
13
|
Max: 120
|
12
14
|
Metrics/MethodLength:
|
13
|
-
Max:
|
15
|
+
Max: 20
|
16
|
+
Metrics/AbcSize:
|
17
|
+
Max: 30
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ And then execute:
|
|
20
20
|
Or install it yourself as:
|
21
21
|
|
22
22
|
$ gem install easy_encoding
|
23
|
-
|
23
|
+
|
24
24
|
## Configuration
|
25
25
|
You can configure symbol for left and right node of tree.
|
26
26
|
```ruby
|
@@ -47,6 +47,21 @@ huffman.frequencies #=> {:x7=>0.42, :x3=>0.28, :x6=>0.1, :x5=>0.1, :x
|
|
47
47
|
huffman.char_codes #=> {:x7=>"1", :x3=>"01", :x5=>"0000", :x6=>"0001", :x4=>"0011", :x2=>"00100", :x1=>"00101"}
|
48
48
|
```
|
49
49
|
|
50
|
+
#### Shannon-Fano coding
|
51
|
+
|
52
|
+
Using with string:
|
53
|
+
```ruby
|
54
|
+
shannon_fano = EasyEncoding::ShannonFano.new('Code')
|
55
|
+
shannon_fano.frequencies #=> {"e"=>0.25, "d"=>0.25, "o"=>0.25, "c"=>0.25}
|
56
|
+
shannon_fano.char_codes #=> {"e"=>"11", "d"=>"10", "o"=>"01", "c"=>"00"}
|
57
|
+
```
|
58
|
+
Using with frequencies:
|
59
|
+
```ruby
|
60
|
+
shannon_fano = EasyEncoding::ShannonFano.new({ x7: 0.42, x3: 0.28, x5: 0.1, x6: 0.1, x4: 0.05, x2: 0.03, x1: 0.02 })
|
61
|
+
shannon_fano.frequencies #=> {:x7=>0.42, :x3=>0.28, :x5=>0.1, :x6=>0.1, :x4=>0.05, :x2=>0.03, :x1=>0.02}
|
62
|
+
shannon_fano.char_codes #=> {:x7=>"1", :x3=>"01", :x6=>"0011", :x5=>"0010", :x4=>"0001", :x2=>"00001", :x1=>"00000"}
|
63
|
+
```
|
64
|
+
|
50
65
|
## Contributing
|
51
66
|
|
52
67
|
See [CONTRIBUTING.md](https://github.com/floor114/easy_encoding/blob/master/CONTRIBUTING.md).
|
data/lib/easy_encoding.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
module EasyEncoding
|
2
|
+
class Base
|
3
|
+
attr_reader :input
|
4
|
+
|
5
|
+
def initialize(input)
|
6
|
+
@input = input
|
7
|
+
end
|
8
|
+
|
9
|
+
def char_codes
|
10
|
+
@char_codes ||= generate_codes!
|
11
|
+
end
|
12
|
+
|
13
|
+
def frequencies
|
14
|
+
@frequencies ||= calculate_frequencies!
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def generate_codes!; end
|
20
|
+
|
21
|
+
def calculate_frequencies!
|
22
|
+
case input
|
23
|
+
when Hash
|
24
|
+
raise ArgumentError, 'summ of frequencies should eq 1' if valid_hash_frequencies?
|
25
|
+
hash_frequencies
|
26
|
+
when String
|
27
|
+
string_frequencies
|
28
|
+
else
|
29
|
+
raise ArgumentError, 'you must provide a hash or a string'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def string_frequencies
|
34
|
+
frequencies = Hash.new(0.0)
|
35
|
+
frequencies.tap { |freq| input.each_char { |char| freq[char.to_sym] += 1 } }
|
36
|
+
.each { |key, value| frequencies[key] = value / input.size }
|
37
|
+
.sort_by { |_, value| value }.reverse.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def hash_frequencies
|
41
|
+
input.sort_by(&:last).reverse.to_h
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_hash_frequencies?
|
45
|
+
input.values.reduce(:+) > 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,40 +1,21 @@
|
|
1
1
|
require 'easy_encoding/node'
|
2
|
+
require 'easy_encoding/base'
|
2
3
|
|
3
4
|
module EasyEncoding
|
4
|
-
class Huffman
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(input)
|
8
|
-
case input
|
9
|
-
when Hash
|
10
|
-
raise ArgumentError, 'summ of frequencies should eq 1' if input.values.reduce(:+) > 1
|
11
|
-
@frequencies = input.sort_by { |_, value| value }.reverse.to_h
|
12
|
-
when String
|
13
|
-
@input = input
|
14
|
-
@frequencies = calculate_frequencies(input)
|
15
|
-
else
|
16
|
-
raise ArgumentError, 'you must provide a hash or a string'
|
17
|
-
end
|
18
|
-
@root = create_tree(frequencies)
|
19
|
-
@char_codes = generate_codes(root)
|
5
|
+
class Huffman < Base
|
6
|
+
def root
|
7
|
+
@root ||= create_tree!
|
20
8
|
end
|
21
9
|
|
22
10
|
private
|
23
11
|
|
24
|
-
def generate_codes
|
25
|
-
{}.tap { |
|
12
|
+
def generate_codes!
|
13
|
+
{}.tap { |res| root.walk { |node, code| res[node.symbol] = code unless node.merged? } }
|
26
14
|
.sort_by { |_, value| value.length }.to_h
|
27
15
|
end
|
28
16
|
|
29
|
-
def
|
30
|
-
|
31
|
-
frequencies.tap { |freq| string.each_char { |char| freq[char.to_sym] += 1 } }
|
32
|
-
.each { |key, value| frequencies[key] = value / string.size }
|
33
|
-
.sort_by { |_, value| value }.reverse.to_h
|
34
|
-
end
|
35
|
-
|
36
|
-
def create_tree(frequencies)
|
37
|
-
nodes = [].tap { |result| frequencies.each { |sym, freq| result << Node.new(symbol: sym, frequency: freq) } }
|
17
|
+
def create_tree!
|
18
|
+
nodes = [].tap { |res| frequencies.each { |sym, freq| res << Node.new(symbol: sym, frequency: freq) } }
|
38
19
|
|
39
20
|
while nodes.size > 1
|
40
21
|
nodes.sort!
|
data/lib/easy_encoding/node.rb
CHANGED
@@ -9,10 +9,10 @@ module EasyEncoding
|
|
9
9
|
|
10
10
|
def initialize(params)
|
11
11
|
@frequency = params.fetch(:frequency, 0)
|
12
|
-
@symbol
|
13
|
-
@left
|
14
|
-
@right
|
15
|
-
@parent
|
12
|
+
@symbol = params.fetch(:symbol, '')
|
13
|
+
@left = params[:left]
|
14
|
+
@right = params[:right]
|
15
|
+
@parent = params[:parent]
|
16
16
|
end
|
17
17
|
|
18
18
|
def walk(&block)
|
@@ -21,13 +21,11 @@ module EasyEncoding
|
|
21
21
|
|
22
22
|
def walk_node(code, &block)
|
23
23
|
yield(self, code)
|
24
|
-
left&.walk_node(code + EasyEncoding.configuration.left_node_symbol
|
25
|
-
right&.walk_node(code + EasyEncoding.configuration.right_node_symbol
|
24
|
+
left&.walk_node(code + EasyEncoding.configuration.left_node_symbol, &block)
|
25
|
+
right&.walk_node(code + EasyEncoding.configuration.right_node_symbol, &block)
|
26
26
|
end
|
27
27
|
|
28
28
|
def <=>(other)
|
29
|
-
return nil unless other.is_a?(self.class)
|
30
|
-
|
31
29
|
frequency <=> other.frequency
|
32
30
|
end
|
33
31
|
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'easy_encoding/base'
|
2
|
+
|
3
|
+
module EasyEncoding
|
4
|
+
class ShannonFano < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def generate_codes!
|
8
|
+
divide_and_encode(frequencies)
|
9
|
+
end
|
10
|
+
|
11
|
+
def divide_and_encode(hash)
|
12
|
+
return if hash.size == 1
|
13
|
+
return_hash = Hash.new('')
|
14
|
+
|
15
|
+
right_hash = hash.clone
|
16
|
+
left_hash = {}
|
17
|
+
|
18
|
+
old_diff = right_hash.values.reduce(:+)
|
19
|
+
move_key_value!(left_hash, right_hash)
|
20
|
+
right_summ = right_hash.values.reduce(:+)
|
21
|
+
left_summ = left_hash.values.reduce(:+)
|
22
|
+
|
23
|
+
new_diff = (left_summ - right_summ).abs
|
24
|
+
|
25
|
+
while new_diff < old_diff
|
26
|
+
break if right_hash.size == 1
|
27
|
+
left_summ, right_summ = left_right_summ(left_hash, right_hash)
|
28
|
+
old_diff, new_diff = recalculate_diffs(left_summ, right_summ, new_diff)
|
29
|
+
move_key_value!(left_hash, right_hash) if old_diff >= new_diff
|
30
|
+
end
|
31
|
+
|
32
|
+
merge_codes!(left_hash, right_hash, return_hash)
|
33
|
+
walk_hash!(left_hash, return_hash)
|
34
|
+
walk_hash!(right_hash, return_hash)
|
35
|
+
|
36
|
+
return_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def move_key_value!(left_hash, right_hash)
|
40
|
+
left_hash[right_hash.keys[0]] = right_hash.delete(right_hash.keys[0])
|
41
|
+
end
|
42
|
+
|
43
|
+
def left_right_summ(left_hash, right_hash)
|
44
|
+
right_summ = right_hash.values[1..-1].reduce(:+)
|
45
|
+
left_summ = left_hash.values.reduce(:+) + right_hash.values[0]
|
46
|
+
|
47
|
+
[left_summ, right_summ]
|
48
|
+
end
|
49
|
+
|
50
|
+
def recalculate_diffs(left_summ, right_summ, diff)
|
51
|
+
old_diff = diff
|
52
|
+
new_diff = (left_summ - right_summ).abs
|
53
|
+
|
54
|
+
[old_diff, new_diff]
|
55
|
+
end
|
56
|
+
|
57
|
+
def merge_codes!(left_hash, right_hash, return_hash)
|
58
|
+
left_hash.keys.each { |key| return_hash[key] += EasyEncoding.configuration.left_node_symbol }
|
59
|
+
right_hash.keys.each { |key| return_hash[key] += EasyEncoding.configuration.right_node_symbol }
|
60
|
+
end
|
61
|
+
|
62
|
+
def walk_hash!(hash, return_hash)
|
63
|
+
return_hash.merge!(divide_and_encode(hash)) { |_, val1, val2| val1 + val2 } if hash.size != 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easy_encoding
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taras Shpachenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -87,9 +87,11 @@ files:
|
|
87
87
|
- Rakefile
|
88
88
|
- easy_encoding.gemspec
|
89
89
|
- lib/easy_encoding.rb
|
90
|
+
- lib/easy_encoding/base.rb
|
90
91
|
- lib/easy_encoding/configuration.rb
|
91
92
|
- lib/easy_encoding/huffman.rb
|
92
93
|
- lib/easy_encoding/node.rb
|
94
|
+
- lib/easy_encoding/shannon_fano.rb
|
93
95
|
- lib/easy_encoding/version.rb
|
94
96
|
homepage: https://github.com/floor114/easy_encoding
|
95
97
|
licenses:
|