falafel 0.0.2.1 → 0.0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5180f16b8868a35cf65faa396c7b341166604e2aaf7db8d9f7099c819630497f
4
- data.tar.gz: 7c773f6a53d8895333d37115cba598dcf60128bff2eaf4dc47e73f7e1ca21298
3
+ metadata.gz: 754e7aa62a91e0f16ed875b859d8e208379df55509569dbd5d5a38e93b874fbe
4
+ data.tar.gz: bcbb64b7d4627514c2e3560b80e15ccc3f0dbf721448b96247188f778d8f897c
5
5
  SHA512:
6
- metadata.gz: 0b7470e125d1f803eacc1d207704b90782e439fef8c7fe00dcf0acdb6c27324d24ed2da0666b3c456fe7cc7b255902002f20870e8f93d589482d4d1df3370aca
7
- data.tar.gz: c8534f9da1cfec2623caa5cf0422f3d03009579374d2183a10341398a93aad87fbf2a0e85aaba0a0a766ee1d8ae62baa02e39bd2a76c7857fa6613629ae64f5a
6
+ metadata.gz: 8fda2266343ea3c9c919898f8ebd0381329189cf6eb08f3e281ba20e30e950d6d1bac77356ff91263c7377e77c808c1b0cb224b705dda1f3970b67b294242d9f
7
+ data.tar.gz: b9e9c7b8552c38d9a3f09143e68ac4cb78b5527899052a79ec975e1b6a08b45cef97158c3bc785f9f05bb1267943c38b7fc37a8575ea86ed409bd72a4f5317d8
data/lib/cfg.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'cyk'
4
- require_relative 'chomsky_nf'
5
- require_relative 'epsilon_free'
6
- require_relative 'chaining_free'
3
+ require_relative 'cfg_helper/cyk'
4
+ require_relative 'cfg_helper/chomsky_nf'
5
+ require_relative 'cfg_helper/epsilon_free'
6
+ require_relative 'cfg_helper/chaining_free'
7
7
 
8
8
  # Samll CFG impletation
9
9
  # Generate words and check if words are the @lang
@@ -35,26 +35,26 @@ class CFG
35
35
  end
36
36
 
37
37
  def epsilon_free(custom_rule)
38
- e_free = EpsilonFree.new
38
+ e_free = CFGHelper::EpsilonFree.new
39
39
  @rules_ef_res = e_free.run custom_rule || @rules
40
40
  @rules_ef = e_free.rebuild_rules @rules, @rules_ef_res
41
41
  end
42
42
 
43
43
  def chaining_free
44
- c_free = ChainingFree.new
44
+ c_free = CFGHelper::ChainingFree.new
45
45
  @rules_cf_res = c_free.run @rules, @vars
46
46
  @rules_cf = c_free.rebuild_rules @rules_cf_res
47
47
  end
48
48
 
49
49
  def chomsky_nf(custom_rule)
50
- chomsky = ChomskyNF.new
50
+ chomsky = CFGHelper::ChomskyNF.new
51
51
  rules = chomsky.run custom_rule || @rules, @alphabet
52
52
 
53
53
  @chomsky_nf_rules = chomsky.simplify rules
54
54
  end
55
55
 
56
56
  def cyk_run(word)
57
- cyk = CYK.new word, @chomsky_nf_rules
57
+ cyk = CFGHelper::CYK.new word, @chomsky_nf_rules
58
58
 
59
59
  cyk.run
60
60
 
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CFGHelper
4
+ # remove chaining rules from CFG
5
+ class ChainingFree
6
+ def run(rules, vars)
7
+ @rules = rules
8
+ @vars = vars
9
+ c_r = _chaining_relation
10
+
11
+ # build transivity relation from _chaining_relation(K) as A
12
+ # remove _chaining_relation from rules
13
+ _rebuild_rules + c_r.map { |r| _transitivity_relation r }.reduce(:concat) - c_r
14
+ end
15
+
16
+ def rebuild_rules(current_rules)
17
+ res = {}
18
+
19
+ @vars.each { |v| res[v] = [] }
20
+
21
+ current_rules.each do |l, r|
22
+ res[l] << r.chars unless res[l].include? r.chars
23
+ end
24
+
25
+ res
26
+ end
27
+
28
+ private
29
+
30
+ def _chaining_relation
31
+ rules = _rebuild_rules
32
+
33
+ rules & @vars.product(@vars)
34
+ end
35
+
36
+ def _rebuild_rules
37
+ result = []
38
+ @rules.each do |var, rule|
39
+ rule.map do |r|
40
+ result << [var, r.join]
41
+ end
42
+ end
43
+
44
+ result
45
+ end
46
+
47
+ def _transitivity_relation(pair)
48
+ transitive_relation = [pair]
49
+
50
+ new_pairs = []
51
+
52
+ _rebuild_rules.each do |a, b|
53
+ next unless pair[1] == a && !transitive_relation.include?([pair[0], b])
54
+
55
+ new_pairs << [pair[0], b]
56
+ end
57
+
58
+ transitive_relation.concat new_pairs
59
+ end
60
+
61
+ def _new_pairs(rules)
62
+ rules.each do |a, b|
63
+ next unless pair[1] == a && !transitive_relation.include?([pair[0], b])
64
+
65
+ new_pairs << [pair[0], b]
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'chomsky_nf_simplifier'
4
+
5
+ module CFGHelper
6
+ # convert to Chomsky Normal Form
7
+ class ChomskyNF
8
+ def run(rules, alphabet)
9
+ new_rules = {}
10
+ @rules = rules
11
+ @alphabet = alphabet
12
+
13
+ # add cases like (A, a), (B, b)
14
+ _add_single_vars new_rules
15
+
16
+ # change rules like (X, aX) to (X, AX)
17
+ _handle_simple_rule new_rules
18
+
19
+ _handle_all_rule new_rules
20
+ end
21
+
22
+ def simplify(rules)
23
+ simplifier = CFGHelper::ChomskyNFSimplifier.new
24
+
25
+ simplifier.run rules, @alphabet
26
+ end
27
+
28
+ private
29
+
30
+ def _add_single_vars(new_rules)
31
+ @rules.values.reduce(:concat).each do |rule|
32
+ rule.select { |var| var == var.downcase }.each do |r|
33
+ new_rules[r.upcase] = r
34
+ end
35
+ end
36
+ end
37
+
38
+ def _handle_simple_rule(new_rules)
39
+ @rules.each do |var, rule|
40
+ new_rules[var] = []
41
+ rule.each do |r|
42
+ next if r.empty?
43
+
44
+ new_rules[var] << r.map(&:upcase)
45
+ end
46
+ end
47
+ end
48
+
49
+ def _handle_all_rule(new_rules)
50
+ new_rules_buffer = []
51
+
52
+ new_rules.each do |var, rules|
53
+ next if _is_character? rules
54
+
55
+ new_rules_buffer << _new_rules_buffer(rules, var)
56
+ end
57
+
58
+ new_rules.merge! new_rules_buffer.reduce(&:merge)
59
+ end
60
+
61
+ def _is_character?(value)
62
+ value.is_a?(String) && value.length == 1
63
+ end
64
+
65
+ def _new_rules_buffer(rules, var)
66
+ helper_vars = _helper_vars rules
67
+ helper_vars.merge! @alphabet.each_with_object({}) { |ele, meme| meme[ele.capitalize] = ele.capitalize }
68
+
69
+ _new_rules rules, var, helper_vars
70
+ end
71
+
72
+ def _check_simplify(rule, holder, current_var)
73
+ return false unless rule.size == 1
74
+
75
+ holder[current_var] << rule.last unless holder[current_var].include? rule
76
+
77
+ true
78
+ end
79
+
80
+ def _new_rules(rules, var, helper_vars)
81
+ holder = {}
82
+
83
+ rules.each do |rule|
84
+ rest = ''
85
+ rule.each_with_index do |head, index|
86
+ current_var = index.zero? ? var : rest
87
+ holder[current_var] ||= []
88
+
89
+ is_simple = _check_simplify rule, holder, current_var
90
+
91
+ break if is_simple
92
+
93
+ rest = _chomsky_nf_vars index, rule, helper_vars
94
+
95
+ nf_rest = "#{head}#{rest}"
96
+
97
+ if index + 2 == rule.size
98
+ if rest.nil?
99
+ rest = rule.last
100
+ nf_rest += rest
101
+ end
102
+
103
+ holder[current_var] << nf_rest unless holder[current_var].include? nf_rest
104
+
105
+ break
106
+ else
107
+ holder[current_var] << nf_rest unless holder[current_var].include? nf_rest
108
+ end
109
+ end
110
+ end
111
+
112
+ holder
113
+ end
114
+
115
+ def _chomsky_nf_vars(index, rule, helper_vars)
116
+ rule_size = rule.size
117
+ rest = rule[(index + 1)..rule_size].join
118
+
119
+ helper_vars.key(rest)
120
+ end
121
+
122
+ def _helper_vars(rules)
123
+ helper_vars = {}
124
+
125
+ rules.each do |rule|
126
+ rule.each_with_index do |_, index|
127
+ letter, rest = _chomsky_nf_helper_vars index, rule, helper_vars.keys
128
+
129
+ break if index + 2 == rule.size
130
+
131
+ next if helper_vars.values.include? rest
132
+
133
+ helper_vars[letter] = rest unless helper_vars.key?(letter) && rest.size > 1
134
+ end
135
+ end
136
+
137
+ helper_vars
138
+ end
139
+
140
+ def _chomsky_nf_helper_vars(index, rule, helper_vars)
141
+ rule_size = rule.size
142
+ letter = helper_vars.empty? ? _find_letter(index) : helper_vars.sort!.last.succ
143
+ rest = rule[(index + 1)..rule_size].join
144
+
145
+ [letter, rest]
146
+ end
147
+
148
+ def _find_letter(n)
149
+ result = 'H'
150
+ n.times { result = result.succ }
151
+
152
+ result
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CFGHelper
4
+ # simplify chomsky normal form
5
+ class ChomskyNFSimplifier
6
+ def run(new_rules, alphabet)
7
+ vars_with_one_letter = _vars_with_one_letter new_rules, alphabet
8
+
9
+ return new_rules if vars_with_one_letter.empty?
10
+
11
+ extendible_rules = _find_extendible_rules new_rules, vars_with_one_letter.keys
12
+
13
+ return new_rules if extendible_rules.empty?
14
+
15
+ missing_rules = _missing_rules extendible_rules, vars_with_one_letter
16
+
17
+ _add_missing_rules missing_rules, new_rules
18
+
19
+ new_rules
20
+ end
21
+
22
+ private
23
+
24
+ def _vars_with_one_letter(new_rules, alphabet)
25
+ vars = {}
26
+
27
+ new_rules.each do |key, values|
28
+ # skip simple rules like (A, a), (B, b),...
29
+ next if values.size == 1
30
+
31
+ letters = values.select { |val| _is_letter val, alphabet }.uniq
32
+ vars[key] = letters
33
+ end
34
+
35
+ vars
36
+ end
37
+
38
+ def _is_letter(val, alphabet)
39
+ val.size == 1 && alphabet.include?(val.downcase)
40
+ end
41
+
42
+ def _find_extendible_rules(new_rules, rules_keys)
43
+ extendible = {}
44
+
45
+ filterd_rules = new_rules.reject { |_, rules| rules.is_a?(String) }
46
+
47
+ filterd_rules.each do |letter, rules|
48
+ rules_keys.each do |rules_key|
49
+ rules.each do |rule|
50
+ next unless rule.include?(rules_key)
51
+
52
+ extendible[letter] ||= []
53
+ extendible[letter] << rule
54
+ end
55
+ end
56
+ end
57
+
58
+ extendible
59
+ end
60
+
61
+ def _missing_rules(extendible_rules, vars)
62
+ res = {}
63
+
64
+ extendible_rules.each do |var_rule, nfs|
65
+ nfs.each do |nf|
66
+ vars.each do |match_char, replacement_chars|
67
+ replacement_chars.each do |rc|
68
+ res[var_rule] ||= []
69
+ res[var_rule] << _combinations(nf, rc, match_char)
70
+ end
71
+ end
72
+
73
+ res[var_rule] = res[var_rule]&.flatten&.uniq
74
+
75
+ _check_special_case nf, res, var_rule, vars
76
+ end
77
+ end
78
+
79
+ res
80
+ end
81
+
82
+ def _combinations(original_string, replacement_char, match_char)
83
+ combinations = []
84
+
85
+ 0.upto(1) do |i|
86
+ 0.upto(1) do |j|
87
+ new_rule = original_string.dup
88
+ new_rule[0] = replacement_char if i == 1 && original_string[0] == match_char
89
+ new_rule[1] = replacement_char if j == 1 && original_string[1] == match_char
90
+ combinations << new_rule
91
+ end
92
+ end
93
+
94
+ combinations.uniq
95
+ end
96
+
97
+ def _add_missing_rules(missing_rules, new_rules)
98
+ missing_rules.each do |key, val|
99
+ next if val.nil?
100
+
101
+ new_rules[key].concat(val).uniq!
102
+ end
103
+ end
104
+
105
+ def _check_special_case(nf, res, var_rule, vars)
106
+ vars.each do |match_char, combi|
107
+ next unless nf == match_char * 2
108
+
109
+ missing_rules = combi.map { |lft| combi.map { |rgt| "#{lft}#{rgt}" } }.flatten
110
+
111
+ res[var_rule].concat(missing_rules)
112
+ end
113
+
114
+ res
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CFGHelper
4
+ # Implemention of cyk algo.
5
+ class CYK
6
+ attr_reader :matrix, :is_in_l
7
+
8
+ def initialize(word, custom_rule)
9
+ @word = word
10
+ @rules = custom_rule.select { |_, val| val.is_a?(Array) }
11
+ @helper_vars = @rules.values.flatten
12
+ end
13
+
14
+ def run
15
+ _cyk_fill_diagonal
16
+ _cyk_fill_matrix
17
+ @is_in_l = _is_in_l?
18
+ end
19
+
20
+ private
21
+
22
+ def _cyk_fill_diagonal
23
+ wrd_lng = @word.length
24
+ @matrix = wrd_lng.times.map { wrd_lng.times.map { [] } }
25
+
26
+ (0..wrd_lng - 1).each do |index|
27
+ @matrix[index][index] = @word[index].upcase
28
+ end
29
+ end
30
+
31
+ def _cyk_fill_matrix
32
+ @matrix.size.times do |limiter|
33
+ (0...@matrix.length - limiter).each do |i|
34
+ j = i + limiter
35
+
36
+ next if i == j
37
+
38
+ helper_var = _helper_var i, j
39
+ matrix_ele_info = _matrix_ele_info i, j
40
+ @matrix[i][j] = _add_to_matrix helper_var, matrix_ele_info
41
+ end
42
+ end
43
+ end
44
+
45
+ def _helper_var(row, col)
46
+ res = '0'
47
+
48
+ (row..col - 1).step(1) do |h|
49
+ p_ = @matrix[row][h]
50
+ q_ = @matrix[h + 1][col]
51
+ res = "#{p_}#{q_}"
52
+
53
+ break if @helper_vars.include? res
54
+ end
55
+
56
+ res
57
+ end
58
+
59
+ def _matrix_ele_info(i, j)
60
+ res = {}
61
+
62
+ res['i'] = i
63
+ res['j'] = j
64
+ res['row_c'] = @matrix.count
65
+
66
+ res
67
+ end
68
+
69
+ def _add_to_matrix(helper_var, matrix_ele_info)
70
+ matrix_ele = '0'
71
+ return if helper_var == matrix_ele
72
+
73
+ keys = []
74
+
75
+ @rules.each do |key, vals|
76
+ vals.each do |val|
77
+ keys << key if val == helper_var
78
+ end
79
+ end
80
+
81
+ _matrix_ele keys, matrix_ele_info
82
+ end
83
+
84
+ def _matrix_ele(keys, matrix_ele_info)
85
+ return 'S' if keys.include?('S') && _is_last_element?(matrix_ele_info)
86
+
87
+ return keys.last if keys.size == 1
88
+
89
+ keys.reject { |key| key == 'S' }.last || '0'
90
+ end
91
+
92
+ def _is_last_element?(matrix_ele_info)
93
+ matrix_ele_info['i'].zero? && matrix_ele_info['j'] == matrix_ele_info['row_c'] - 1
94
+ end
95
+
96
+ def _is_in_l?
97
+ @matrix.first.last == 'S'
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CFGHelper
4
+ # used to clear a CFG from the epsilon rules
5
+ class EpsilonFree
6
+ def run(rules)
7
+ epsilon = _epsilon rules
8
+ rules_ef = {}
9
+
10
+ return if epsilon.empty?
11
+
12
+ epsilon.each do |e_class|
13
+ cleared_rules = _cleared_rules rules[e_class]
14
+ epsilon_free_word = cleared_rules.map(&:join)
15
+ grammer = _grammer_epsilon_free epsilon_free_word, e_class
16
+ rules_ef[e_class] = grammer
17
+ end
18
+
19
+ rules_ef
20
+ end
21
+
22
+ def rebuild_rules(current_rules, rules_epsilon_free)
23
+ missing_vars = current_rules.keys - rules_epsilon_free.keys
24
+
25
+ res = {}
26
+ rules_epsilon_free.each do |key, rules|
27
+ res[key] = []
28
+ rules.each do |rule|
29
+ res[key] << rule.chars
30
+ end
31
+ end
32
+
33
+ missing_vars.each { |v| res[v] = current_rules[v] }
34
+
35
+ res
36
+ end
37
+
38
+ private
39
+
40
+ def _epsilon(rules)
41
+ res = rules.map do |var, rule|
42
+ next unless rule.include? []
43
+
44
+ var
45
+ end
46
+ res.reject(&:nil?)
47
+ end
48
+
49
+ def _cleared_rules(rules)
50
+ rules.reject(&:empty?)
51
+ end
52
+
53
+ def _grammer_epsilon_free(epsilon_free_word, e_class)
54
+ rules_epsilon_location = _new_rules_epsilon_location epsilon_free_word, e_class
55
+
56
+ res = []
57
+ rules_epsilon_location.map do |rule, possibilities|
58
+ possibilities.each do |possibility|
59
+ res << _remove_e_class(possibility, rule.split(''))
60
+ end
61
+
62
+ res << epsilon_free_word.delete(e_class) if possibilities.size == 1
63
+ end
64
+
65
+ res.uniq.reject(&:nil?)
66
+ end
67
+
68
+ def _new_rules_epsilon_location(s_rule, e_class)
69
+ res = {}
70
+ s_rule.each do |rule|
71
+ s_index = []
72
+ rule.each_char.with_index { |char, index| s_index << index if char == e_class }
73
+ res[rule] = _power_set(s_index)
74
+ end
75
+
76
+ res
77
+ end
78
+
79
+ def _power_set(set)
80
+ if set.empty?
81
+ [[]]
82
+ else
83
+ element = set[0]
84
+ subsets = _power_set set[1..]
85
+ subsets + subsets.map { |subset| [element] + subset }
86
+ end
87
+ end
88
+
89
+ def _remove_e_class(possibility, cleared_rules)
90
+ return cleared_rules.join '' if possibility.empty?
91
+
92
+ new_rule = cleared_rules.join ''
93
+ possibility.reverse.each { |index| new_rule.slice! index }
94
+
95
+ new_rule
96
+ end
97
+ end
98
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: falafel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2.1
4
+ version: 0.0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abed Alkedda
@@ -17,12 +17,12 @@ extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
19
  - lib/cfg.rb
20
- - lib/chaining_free.rb
21
- - lib/chomsky_nf.rb
22
- - lib/chomsky_nf_simplifier.rb
23
- - lib/cyk.rb
20
+ - lib/cfg_helper/chaining_free.rb
21
+ - lib/cfg_helper/chomsky_nf.rb
22
+ - lib/cfg_helper/chomsky_nf_simplifier.rb
23
+ - lib/cfg_helper/cyk.rb
24
+ - lib/cfg_helper/epsilon_free.rb
24
25
  - lib/dfa.rb
25
- - lib/epsilon_free.rb
26
26
  - lib/falafel.rb
27
27
  - lib/pump.rb
28
28
  - lib/rx.rb
data/lib/chaining_free.rb DELETED
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # remove chaining rules from CFG
4
- class ChainingFree
5
- def run(rules, vars)
6
- @rules = rules
7
- @vars = vars
8
- c_r = _chaining_relation
9
-
10
- # build transivity relation from _chaining_relation(K) as A
11
- # remove _chaining_relation from rules
12
- _rebuild_rules + c_r.map { |r| _transitivity_relation r }.reduce(:concat) - c_r
13
- end
14
-
15
- def rebuild_rules(current_rules)
16
- res = {}
17
-
18
- @vars.each { |v| res[v] = [] }
19
-
20
- current_rules.each do |l, r|
21
- res[l] << r.chars unless res[l].include? r.chars
22
- end
23
-
24
- res
25
- end
26
-
27
- private
28
-
29
- def _chaining_relation
30
- rules = _rebuild_rules
31
-
32
- rules & @vars.product(@vars)
33
- end
34
-
35
- def _rebuild_rules
36
- result = []
37
- @rules.each do |var, rule|
38
- rule.map do |r|
39
- result << [var, r.join]
40
- end
41
- end
42
-
43
- result
44
- end
45
-
46
- def _transitivity_relation(pair)
47
- transitive_relation = [pair]
48
-
49
- new_pairs = []
50
-
51
- _rebuild_rules.each do |a, b|
52
- next unless pair[1] == a && !transitive_relation.include?([pair[0], b])
53
-
54
- new_pairs << [pair[0], b]
55
- end
56
-
57
- transitive_relation.concat new_pairs
58
- end
59
-
60
- def _new_pairs(rules)
61
- rules.each do |a, b|
62
- next unless pair[1] == a && !transitive_relation.include?([pair[0], b])
63
-
64
- new_pairs << [pair[0], b]
65
- end
66
- end
67
- end
data/lib/chomsky_nf.rb DELETED
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'chomsky_nf_simplifier'
4
-
5
- # convert to Chomsky Normal Form
6
- class ChomskyNF
7
- def run(rules, alphabet)
8
- new_rules = {}
9
- @rules = rules
10
- @alphabet = alphabet
11
-
12
- # add cases like (A, a), (B, b)
13
- _add_single_vars new_rules
14
-
15
- # change rules like (X, aX) to (X, AX)
16
- _handle_simple_rule new_rules
17
-
18
- _handle_all_rule new_rules
19
- end
20
-
21
- def simplify(rules)
22
- simplifier = ChomskyNFSimplifier.new
23
-
24
- simplifier.run rules, @alphabet
25
- end
26
-
27
- private
28
-
29
- def _add_single_vars(new_rules)
30
- @rules.values.reduce(:concat).each do |rule|
31
- rule.select { |var| var == var.downcase }.each do |r|
32
- new_rules[r.upcase] = r
33
- end
34
- end
35
- end
36
-
37
- def _handle_simple_rule(new_rules)
38
- @rules.each do |var, rule|
39
- new_rules[var] = []
40
- rule.each do |r|
41
- next if r.empty?
42
-
43
- new_rules[var] << r.map(&:upcase)
44
- end
45
- end
46
- end
47
-
48
- def _handle_all_rule(new_rules)
49
- new_rules_buffer = []
50
-
51
- new_rules.each do |var, rules|
52
- next if _is_character? rules
53
-
54
- new_rules_buffer << _new_rules_buffer(rules, var)
55
- end
56
-
57
- new_rules.merge! new_rules_buffer.reduce(&:merge)
58
- end
59
-
60
- def _is_character?(value)
61
- value.is_a?(String) && value.length == 1
62
- end
63
-
64
- def _new_rules_buffer(rules, var)
65
- helper_vars = _helper_vars rules
66
- helper_vars.merge! @alphabet.each_with_object({}) { |ele, meme| meme[ele.capitalize] = ele.capitalize }
67
-
68
- _new_rules rules, var, helper_vars
69
- end
70
-
71
- def _check_simplify(rule, holder, current_var)
72
- return false unless rule.size == 1
73
-
74
- holder[current_var] << rule.last unless holder[current_var].include? rule
75
-
76
- true
77
- end
78
-
79
- def _new_rules(rules, var, helper_vars)
80
- holder = {}
81
-
82
- rules.each do |rule|
83
- rest = ''
84
- rule.each_with_index do |head, index|
85
- current_var = index.zero? ? var : rest
86
- holder[current_var] ||= []
87
-
88
- is_simple = _check_simplify rule, holder, current_var
89
-
90
- break if is_simple
91
-
92
- rest = _chomsky_nf_vars index, rule, helper_vars
93
-
94
- nf_rest = "#{head}#{rest}"
95
-
96
- if index + 2 == rule.size
97
- if rest.nil?
98
- rest = rule.last
99
- nf_rest += rest
100
- end
101
-
102
- holder[current_var] << nf_rest unless holder[current_var].include? nf_rest
103
-
104
- break
105
- else
106
- holder[current_var] << nf_rest unless holder[current_var].include? nf_rest
107
- end
108
- end
109
- end
110
-
111
- holder
112
- end
113
-
114
- def _chomsky_nf_vars(index, rule, helper_vars)
115
- rule_size = rule.size
116
- rest = rule[(index + 1)..rule_size].join
117
-
118
- helper_vars.key(rest)
119
- end
120
-
121
- def _helper_vars(rules)
122
- helper_vars = {}
123
-
124
- rules.each do |rule|
125
- rule.each_with_index do |_, index|
126
- letter, rest = _chomsky_nf_helper_vars index, rule, helper_vars.keys
127
-
128
- break if index + 2 == rule.size
129
-
130
- next if helper_vars.values.include? rest
131
-
132
- helper_vars[letter] = rest unless helper_vars.key?(letter) && rest.size > 1
133
- end
134
- end
135
-
136
- helper_vars
137
- end
138
-
139
- def _chomsky_nf_helper_vars(index, rule, helper_vars)
140
- rule_size = rule.size
141
- letter = helper_vars.empty? ? _find_letter(index) : helper_vars.sort!.last.succ
142
- rest = rule[(index + 1)..rule_size].join
143
-
144
- [letter, rest]
145
- end
146
-
147
- def _find_letter(n)
148
- result = 'H'
149
- n.times { result = result.succ }
150
-
151
- result
152
- end
153
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # simplify chomsky normal form
4
- class ChomskyNFSimplifier
5
- def run(new_rules, alphabet)
6
- vars_with_one_letter = _vars_with_one_letter new_rules, alphabet
7
-
8
- return new_rules if vars_with_one_letter.empty?
9
-
10
- extendible_rules = _find_extendible_rules new_rules, vars_with_one_letter.keys
11
-
12
- return new_rules if extendible_rules.empty?
13
-
14
- missing_rules = _missing_rules extendible_rules, vars_with_one_letter
15
-
16
- _add_missing_rules missing_rules, new_rules
17
-
18
- new_rules
19
- end
20
-
21
- private
22
-
23
- def _vars_with_one_letter(new_rules, alphabet)
24
- vars = {}
25
-
26
- new_rules.each do |key, values|
27
- # skip simple rules like (A, a), (B, b),...
28
- next if values.size == 1
29
-
30
- letters = values.select { |val| _is_letter val, alphabet }.uniq
31
- vars[key] = letters
32
- end
33
-
34
- vars
35
- end
36
-
37
- def _is_letter(val, alphabet)
38
- val.size == 1 && alphabet.include?(val.downcase)
39
- end
40
-
41
- def _find_extendible_rules(new_rules, rules_keys)
42
- extendible = {}
43
-
44
- filterd_rules = new_rules.reject { |_, rules| rules.is_a?(String) }
45
-
46
- filterd_rules.each do |letter, rules|
47
- rules_keys.each do |rules_key|
48
- rules.each do |rule|
49
- next unless rule.include?(rules_key)
50
-
51
- extendible[letter] ||= []
52
- extendible[letter] << rule
53
- end
54
- end
55
- end
56
-
57
- extendible
58
- end
59
-
60
- def _missing_rules(extendible_rules, vars)
61
- res = {}
62
-
63
- extendible_rules.each do |var_rule, nfs|
64
- nfs.each do |nf|
65
- vars.each do |match_char, replacement_chars|
66
- replacement_chars.each do |rc|
67
- res[var_rule] ||= []
68
- res[var_rule] << _combinations(nf, rc, match_char)
69
- end
70
- end
71
-
72
- res[var_rule] = res[var_rule]&.flatten&.uniq
73
-
74
- _check_special_case nf, res, var_rule, vars
75
- end
76
- end
77
-
78
- res
79
- end
80
-
81
- def _combinations(original_string, replacement_char, match_char)
82
- combinations = []
83
-
84
- 0.upto(1) do |i|
85
- 0.upto(1) do |j|
86
- new_rule = original_string.dup
87
- new_rule[0] = replacement_char if i == 1 && original_string[0] == match_char
88
- new_rule[1] = replacement_char if j == 1 && original_string[1] == match_char
89
- combinations << new_rule
90
- end
91
- end
92
-
93
- combinations.uniq
94
- end
95
-
96
- def _add_missing_rules(missing_rules, new_rules)
97
- missing_rules.each do |key, val|
98
- next if val.nil?
99
-
100
- new_rules[key].concat(val).uniq!
101
- end
102
- end
103
-
104
- def _check_special_case(nf, res, var_rule, vars)
105
- vars.each do |match_char, combi|
106
- next unless nf == match_char * 2
107
-
108
- missing_rules = combi.map { |lft| combi.map { |rgt| "#{lft}#{rgt}" } }.flatten
109
-
110
- res[var_rule].concat(missing_rules)
111
- end
112
-
113
- res
114
- end
115
- end
data/lib/cyk.rb DELETED
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Implemention of cyk algo.
4
- class CYK
5
- attr_reader :matrix, :is_in_l
6
-
7
- def initialize(word, custom_rule)
8
- @word = word
9
- @rules = custom_rule.select { |_, val| val.is_a?(Array) }
10
- @helper_vars = @rules.values.flatten
11
- end
12
-
13
- def run
14
- _cyk_fill_diagonal
15
- _cyk_fill_matrix
16
- @is_in_l = _is_in_l?
17
- end
18
-
19
- private
20
-
21
- def _cyk_fill_diagonal
22
- wrd_lng = @word.length
23
- @matrix = wrd_lng.times.map { wrd_lng.times.map { [] } }
24
-
25
- (0..wrd_lng - 1).each do |index|
26
- @matrix[index][index] = @word[index].upcase
27
- end
28
- end
29
-
30
- def _cyk_fill_matrix
31
- @matrix.size.times do |limiter|
32
- (0...@matrix.length - limiter).each do |i|
33
- j = i + limiter
34
-
35
- next if i == j
36
-
37
- helper_var = _helper_var i, j
38
- matrix_ele_info = _matrix_ele_info i, j
39
- @matrix[i][j] = _add_to_matrix helper_var, matrix_ele_info
40
- end
41
- end
42
- end
43
-
44
- def _helper_var(row, col)
45
- res = '0'
46
-
47
- (row..col - 1).step(1) do |h|
48
- p_ = @matrix[row][h]
49
- q_ = @matrix[h + 1][col]
50
- res = "#{p_}#{q_}"
51
-
52
- break if @helper_vars.include? res
53
- end
54
-
55
- res
56
- end
57
-
58
- def _matrix_ele_info(i, j)
59
- res = {}
60
-
61
- res['i'] = i
62
- res['j'] = j
63
- res['row_c'] = @matrix.count
64
-
65
- res
66
- end
67
-
68
- def _add_to_matrix(helper_var, matrix_ele_info)
69
- matrix_ele = '0'
70
- return if helper_var == matrix_ele
71
-
72
- keys = []
73
-
74
- @rules.each do |key, vals|
75
- vals.each do |val|
76
- keys << key if val == helper_var
77
- end
78
- end
79
-
80
- _matrix_ele keys, matrix_ele_info
81
- end
82
-
83
- def _matrix_ele(keys, matrix_ele_info)
84
- return 'S' if keys.include?('S') && _is_last_element?(matrix_ele_info)
85
-
86
- return keys.last if keys.size == 1
87
-
88
- keys.reject { |key| key == 'S' }.last || '0'
89
- end
90
-
91
- def _is_last_element?(matrix_ele_info)
92
- matrix_ele_info['i'].zero? && matrix_ele_info['j'] == matrix_ele_info['row_c'] - 1
93
- end
94
-
95
- def _is_in_l?
96
- @matrix.first.last == 'S'
97
- end
98
- end
data/lib/epsilon_free.rb DELETED
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # used to clear a CFG from the epsilon rules
4
- class EpsilonFree
5
- def run(rules)
6
- epsilon = _epsilon rules
7
- rules_ef = {}
8
-
9
- return if epsilon.empty?
10
-
11
- epsilon.each do |e_class|
12
- cleared_rules = _cleared_rules rules[e_class]
13
- epsilon_free_word = cleared_rules.map(&:join)
14
- grammer = _grammer_epsilon_free epsilon_free_word, e_class
15
- rules_ef[e_class] = grammer
16
- end
17
-
18
- rules_ef
19
- end
20
-
21
- def rebuild_rules(current_rules, rules_epsilon_free)
22
- missing_vars = current_rules.keys - rules_epsilon_free.keys
23
-
24
- res = {}
25
- rules_epsilon_free.each do |key, rules|
26
- res[key] = []
27
- rules.each do |rule|
28
- res[key] << rule.chars
29
- end
30
- end
31
-
32
- missing_vars.each { |v| res[v] = current_rules[v] }
33
-
34
- res
35
- end
36
-
37
- private
38
-
39
- def _epsilon(rules)
40
- res = rules.map do |var, rule|
41
- next unless rule.include? []
42
-
43
- var
44
- end
45
- res.reject(&:nil?)
46
- end
47
-
48
- def _cleared_rules(rules)
49
- rules.reject(&:empty?)
50
- end
51
-
52
- def _grammer_epsilon_free(epsilon_free_word, e_class)
53
- rules_epsilon_location = _new_rules_epsilon_location epsilon_free_word, e_class
54
-
55
- res = []
56
- rules_epsilon_location.map do |rule, possibilities|
57
- possibilities.each do |possibility|
58
- res << _remove_e_class(possibility, rule.split(''))
59
- end
60
-
61
- res << epsilon_free_word.delete(e_class) if possibilities.size == 1
62
- end
63
-
64
- res.uniq.reject(&:nil?)
65
- end
66
-
67
- def _new_rules_epsilon_location(s_rule, e_class)
68
- res = {}
69
- s_rule.each do |rule|
70
- s_index = []
71
- rule.each_char.with_index { |char, index| s_index << index if char == e_class }
72
- res[rule] = _power_set(s_index)
73
- end
74
-
75
- res
76
- end
77
-
78
- def _power_set(set)
79
- if set.empty?
80
- [[]]
81
- else
82
- element = set[0]
83
- subsets = _power_set set[1..]
84
- subsets + subsets.map { |subset| [element] + subset }
85
- end
86
- end
87
-
88
- def _remove_e_class(possibility, cleared_rules)
89
- return cleared_rules.join '' if possibility.empty?
90
-
91
- new_rule = cleared_rules.join ''
92
- possibility.reverse.each { |index| new_rule.slice! index }
93
-
94
- new_rule
95
- end
96
- end