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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a62cc2da992ee357341aa084ed2296458fdb71ca
4
- data.tar.gz: f9e3254396fb2c1e53e180e9bcb17826fd68bba0
3
+ metadata.gz: 657a415e4bace49a68960ffb9d60a5046f43f8dc
4
+ data.tar.gz: 82fb47f7af8a5c8a95b679a05cc6dbb433083410
5
5
  SHA512:
6
- metadata.gz: 6572c24d1047e650d3ced32ce5c804d461aa7ceabb13f9af2d7f569907f1e00008038e849ef5ef8629606a886bdd3d6262589cd76960548754347963f8b306df
7
- data.tar.gz: 7ac1460d65857fb94091103ae36ebb2239cb2816187aaaa71eeed6f0faee58e26bf9ec8eae62bbe3b12e2474790773d3a695f0c813521db7a611b0b100044d58
6
+ metadata.gz: b2bc4d087b8f8a135e45a053db2fb34ae9c6a6f0fba234cef3d10980f5d4945aa1cfa0f1ff3585b832ac09f064965101b10d9d4bae4d904bccf26a3c5eecbcd7
7
+ data.tar.gz: 3a85acd7d59eba8b3428e4b6ae0d61870c203f363992b69f3e16226e47b415958012178279ca1e7a79878e2c9f9aae1bee4ba8d73d43f355a29f262af10cb7c4
@@ -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
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).
@@ -1,6 +1,7 @@
1
1
  require 'easy_encoding/version'
2
2
  require 'easy_encoding/configuration'
3
3
  require 'easy_encoding/huffman'
4
+ require 'easy_encoding/shannon_fano'
4
5
 
5
6
  module EasyEncoding
6
7
  class << self
@@ -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
@@ -3,8 +3,8 @@ module EasyEncoding
3
3
  attr_accessor :right_node_symbol, :left_node_symbol
4
4
 
5
5
  def initialize
6
- @right_node_symbol = 1
7
- @left_node_symbol = 0
6
+ @right_node_symbol = '1'
7
+ @left_node_symbol = '0'
8
8
  end
9
9
  end
10
10
  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
- attr_reader :input, :char_codes, :frequencies, :root
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(root)
25
- {}.tap { |result| root.walk { |node, code| result[node.symbol] = code unless node.merged? } }
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 calculate_frequencies(string)
30
- frequencies = Hash.new(0.0)
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!
@@ -9,10 +9,10 @@ module EasyEncoding
9
9
 
10
10
  def initialize(params)
11
11
  @frequency = params.fetch(:frequency, 0)
12
- @symbol = params.fetch(:symbol, '')
13
- @left = params.fetch(:left, nil)
14
- @right = params.fetch(:right, nil)
15
- @parent = params.fetch(:parent, nil)
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.to_s, &block)
25
- right&.walk_node(code + EasyEncoding.configuration.right_node_symbol.to_s, &block)
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
@@ -1,3 +1,3 @@
1
1
  module EasyEncoding
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  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.1
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: 2016-11-10 00:00:00.000000000 Z
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: