falafel 0.0.1.1 → 0.0.2.1

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
  SHA256:
3
- metadata.gz: 796b681163a3d9d57b47cadcb95f1d5e2e9af1e97a0b841b2e31ddc9c725769b
4
- data.tar.gz: 3811e2bc49acfee5aa9a4e4f27569df022fb68c2ddafbafa10b43a7c92afe4d8
3
+ metadata.gz: 5180f16b8868a35cf65faa396c7b341166604e2aaf7db8d9f7099c819630497f
4
+ data.tar.gz: 7c773f6a53d8895333d37115cba598dcf60128bff2eaf4dc47e73f7e1ca21298
5
5
  SHA512:
6
- metadata.gz: 96bf15557a50f7a81c8a71d200a0876f7fc445d64d017d3c2011fa088457d61e05327e8ea39c7147d349049a8e8b3811a815c92e04f414109c4505782a8c6613
7
- data.tar.gz: 45573ad63969221aed699f9412d45409c4f72a26c1ec3e83e3bcb4c5fba03c6fb9bdae80d61b3c0a046e4c25a66a00e7c64c00a1841142de675e7eaa45158876
6
+ metadata.gz: 0b7470e125d1f803eacc1d207704b90782e439fef8c7fe00dcf0acdb6c27324d24ed2da0666b3c456fe7cc7b255902002f20870e8f93d589482d4d1df3370aca
7
+ data.tar.gz: c8534f9da1cfec2623caa5cf0422f3d03009579374d2183a10341398a93aad87fbf2a0e85aaba0a0a766ee1d8ae62baa02e39bd2a76c7857fa6613629ae64f5a
data/lib/cfg.rb CHANGED
@@ -10,7 +10,7 @@ require_relative 'chaining_free'
10
10
  # generates random words
11
11
  class CFG
12
12
  attr_accessor :start_var, :rules
13
- attr_reader :rules_ef, :rules_cf, :rnd_words, :reachables,
13
+ attr_reader :rules_ef, :rules_cf, :rnd_words,
14
14
  :rules_ef_res, :rules_cf_res, :chomsky_nf_rules,
15
15
  :cyk_matrix, :is_in_l
16
16
 
@@ -18,7 +18,6 @@ class CFG
18
18
  @start_var = start_var
19
19
  @rules = _rules rules
20
20
  @rnd_words = []
21
- @reachables = []
22
21
  @vars = vars
23
22
  @alphabet = alphabet
24
23
  end
@@ -35,24 +34,9 @@ class CFG
35
34
  end
36
35
  end
37
36
 
38
- def var_reachable?
39
- @rules[@start_var].each do |rule|
40
- @vars.each { |var| @reachables << var if rule.include? var }
41
- end
42
- @reachables.uniq!
43
- end
44
-
45
- def var_productive?
46
- ''
47
- end
48
-
49
- def var_reduced?
50
- ''
51
- end
52
-
53
- def epsilon_free
37
+ def epsilon_free(custom_rule)
54
38
  e_free = EpsilonFree.new
55
- @rules_ef_res = e_free.run @rules
39
+ @rules_ef_res = e_free.run custom_rule || @rules
56
40
  @rules_ef = e_free.rebuild_rules @rules, @rules_ef_res
57
41
  end
58
42
 
data/lib/chomsky_nf.rb CHANGED
@@ -46,15 +46,15 @@ class ChomskyNF
46
46
  end
47
47
 
48
48
  def _handle_all_rule(new_rules)
49
- new_rules_buffer = {}
49
+ new_rules_buffer = []
50
50
 
51
51
  new_rules.each do |var, rules|
52
52
  next if _is_character? rules
53
53
 
54
- new_rules_buffer = _new_rules_buffer rules, var
54
+ new_rules_buffer << _new_rules_buffer(rules, var)
55
55
  end
56
56
 
57
- new_rules.merge! new_rules_buffer
57
+ new_rules.merge! new_rules_buffer.reduce(&:merge)
58
58
  end
59
59
 
60
60
  def _is_character?(value)
@@ -3,15 +3,15 @@
3
3
  # simplify chomsky normal form
4
4
  class ChomskyNFSimplifier
5
5
  def run(new_rules, alphabet)
6
- var_has_one_letter = _var_has_one_letter new_rules, alphabet
6
+ vars_with_one_letter = _vars_with_one_letter new_rules, alphabet
7
7
 
8
- return new_rules if var_has_one_letter.empty?
8
+ return new_rules if vars_with_one_letter.empty?
9
9
 
10
- rules = _find_modify_rules new_rules, var_has_one_letter
10
+ extendible_rules = _find_extendible_rules new_rules, vars_with_one_letter.keys
11
11
 
12
- return new_rules if rules.empty?
12
+ return new_rules if extendible_rules.empty?
13
13
 
14
- missing_rules = _generate_missing_rules rules, var_has_one_letter
14
+ missing_rules = _missing_rules extendible_rules, vars_with_one_letter
15
15
 
16
16
  _add_missing_rules missing_rules, new_rules
17
17
 
@@ -20,56 +20,57 @@ class ChomskyNFSimplifier
20
20
 
21
21
  private
22
22
 
23
- def _var_has_one_letter(new_rules, alphabet)
23
+ def _vars_with_one_letter(new_rules, alphabet)
24
24
  vars = {}
25
25
 
26
26
  new_rules.each do |key, values|
27
+ # skip simple rules like (A, a), (B, b),...
27
28
  next if values.size == 1
28
29
 
29
- values.each do |val|
30
- next unless val.size == 1 && alphabet.include?(val.downcase)
31
-
32
- vars[key] ||= []
33
- vars[key] << val
34
- end
30
+ letters = values.select { |val| _is_letter val, alphabet }.uniq
31
+ vars[key] = letters
35
32
  end
36
33
 
37
34
  vars
38
35
  end
39
36
 
40
- def _find_modify_rules(new_rules, vars)
41
- modify = {}
37
+ def _is_letter(val, alphabet)
38
+ val.size == 1 && alphabet.include?(val.downcase)
39
+ end
42
40
 
43
- new_rules.each do |key, val|
44
- next if val.is_a?(String)
41
+ def _find_extendible_rules(new_rules, rules_keys)
42
+ extendible = {}
45
43
 
46
- val.each do |v|
47
- vars.each_key do |k|
48
- next unless v.include?(k)
44
+ filterd_rules = new_rules.reject { |_, rules| rules.is_a?(String) }
49
45
 
50
- res = val.select { |x| x.include? k }
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)
51
50
 
52
- modify[key] ||= []
53
- modify[key] << res
51
+ extendible[letter] ||= []
52
+ extendible[letter] << rule
54
53
  end
55
54
  end
56
55
  end
57
56
 
58
- modify
57
+ extendible
59
58
  end
60
59
 
61
- def _generate_missing_rules(rules, vars)
60
+ def _missing_rules(extendible_rules, vars)
62
61
  res = {}
63
62
 
64
- rules.each do |var_rule, nfs|
65
- nfs.flatten.each do |nf|
63
+ extendible_rules.each do |var_rule, nfs|
64
+ nfs.each do |nf|
66
65
  vars.each do |match_char, replacement_chars|
67
66
  replacement_chars.each do |rc|
68
- new_rules = _combinations nf, rc, match_char
69
67
  res[var_rule] ||= []
70
- res[var_rule] << new_rules
68
+ res[var_rule] << _combinations(nf, rc, match_char)
71
69
  end
72
70
  end
71
+
72
+ res[var_rule] = res[var_rule]&.flatten&.uniq
73
+
73
74
  _check_special_case nf, res, var_rule, vars
74
75
  end
75
76
  end
@@ -93,7 +94,11 @@ class ChomskyNFSimplifier
93
94
  end
94
95
 
95
96
  def _add_missing_rules(missing_rules, new_rules)
96
- missing_rules.each { |key, val| new_rules[key] = val.flatten.uniq! }
97
+ missing_rules.each do |key, val|
98
+ next if val.nil?
99
+
100
+ new_rules[key].concat(val).uniq!
101
+ end
97
102
  end
98
103
 
99
104
  def _check_special_case(nf, res, var_rule, vars)
@@ -102,7 +107,7 @@ class ChomskyNFSimplifier
102
107
 
103
108
  missing_rules = combi.map { |lft| combi.map { |rgt| "#{lft}#{rgt}" } }.flatten
104
109
 
105
- res[var_rule] << missing_rules
110
+ res[var_rule].concat(missing_rules)
106
111
  end
107
112
 
108
113
  res
data/lib/cyk.rb CHANGED
@@ -13,7 +13,7 @@ class CYK
13
13
  def run
14
14
  _cyk_fill_diagonal
15
15
  _cyk_fill_matrix
16
- _is_in_l?
16
+ @is_in_l = _is_in_l?
17
17
  end
18
18
 
19
19
  private
@@ -34,9 +34,9 @@ class CYK
34
34
 
35
35
  next if i == j
36
36
 
37
- helper_var = _helper_var i, j
38
-
39
- @matrix[i][j] = _add_to_matrix helper_var
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
40
  end
41
41
  end
42
42
  end
@@ -55,20 +55,44 @@ class CYK
55
55
  res
56
56
  end
57
57
 
58
- def _add_to_matrix(rule)
59
- res = '0'
60
- return if rule == res
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 = []
61
73
 
62
74
  @rules.each do |key, vals|
63
75
  vals.each do |val|
64
- res = key if val == rule
76
+ keys << key if val == helper_var
65
77
  end
66
78
  end
67
79
 
68
- res
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
69
93
  end
70
94
 
71
95
  def _is_in_l?
72
- @is_in_l = @matrix.first.last == 'S'
96
+ @matrix.first.last == 'S'
73
97
  end
74
98
  end
data/lib/epsilon_free.rb CHANGED
@@ -61,7 +61,7 @@ class EpsilonFree
61
61
  res << epsilon_free_word.delete(e_class) if possibilities.size == 1
62
62
  end
63
63
 
64
- res
64
+ res.uniq.reject(&:nil?)
65
65
  end
66
66
 
67
67
  def _new_rules_epsilon_location(s_rule, e_class)
data/lib/falafel.rb CHANGED
@@ -104,10 +104,10 @@ class Falafel
104
104
  dfa.to_min
105
105
  end
106
106
 
107
- def pump_lemma
107
+ def pump_lemma(lang, length)
108
108
  require_relative 'pump'
109
109
 
110
- Pump.new lang: nil, word: nil, n: 2, k: 20
110
+ Pump.new lang: lang, length: length
111
111
  end
112
112
 
113
113
  def cfg(alphabet, vars_set, start_var, rules)
@@ -118,7 +118,6 @@ class Falafel
118
118
 
119
119
  private
120
120
 
121
- # alle bilder eine menge m unter r
122
121
  def _image(m, r)
123
122
  m.flat_map { |x| r.map { |y, z| z if x == y }.compact }.sort.uniq
124
123
  end
data/lib/pump.rb CHANGED
@@ -2,29 +2,68 @@
2
2
 
3
3
  # Pump Lemma
4
4
  # It takes language as lambda function and a word as a string
5
- # n is the length of the string you want to pump
6
- # k is the potens of the middle word
5
+ # lang is a regular expression like a^*b^* given as lambda function and set by user
6
+ # word is the word to check pumping
7
+ # length is the length of the string you want to pump
8
+ # return is_regular to tell if lang is regular and decomposition to show why
7
9
  class Pump
8
10
  attr_accessor :lang, :word
11
+ attr_reader :is_regular, :decomposition
9
12
 
10
- def initialize(lang:, word:, n:, k:)
11
- @lang = lang
12
- @word = word
13
- @n = n
14
- @k = k
13
+ def initialize(lang:, length:)
14
+ @lang = lang
15
+ @length = length
16
+ @word = ''
15
17
  end
16
18
 
17
- def run
19
+ def run(show_pros:)
20
+ _clear_old_run
21
+
18
22
  r, s, t = ''
19
23
 
20
- (0...@word.length - @n + 1).each do |i|
21
- r = @word[0...i]
22
- s = @word[i...i + @n]
23
- t = @word[i + @n..]
24
+ @word.length.times do |leng|
25
+ r, s, t = _sigma_chars leng
26
+
27
+ pump_up_down_res = _pump_up_down_res r, s, t, show_pros
28
+ not_in_language = pump_up_down_res.include? false
24
29
 
25
- break if s.length.positive? && (r + s * @k + t) != @word && @lang.call(r + s * @k + t)
30
+ @is_regular = false if not_in_language
31
+
32
+ break if not_in_language
26
33
  end
27
34
 
35
+ @decomposition = [r, s, t]
36
+ end
37
+
38
+ private
39
+
40
+ def _clear_old_run
41
+ @decomposition = []
42
+ @is_regular = true
43
+ end
44
+
45
+ # ∃r, s, t ∈ Σ^∗
46
+ def _sigma_chars(leng)
47
+ r = @word[0...leng] || ''
48
+ s = @word[leng...leng + @length] || ''
49
+ t = @word[leng + @length..] || ''
50
+
28
51
  [r, s, t]
29
52
  end
53
+
54
+ # ∀k ≥ 0 : r·s^k·t ∈ L
55
+ def _pump_up_down_res(r, s, t, show_pros)
56
+ pump_up_down_res = []
57
+
58
+ 20.times do |k|
59
+ puts "r: #{r}, s: #{s}, t: #{t}, k: #{k}, r + s * k + t: #{r + s * k + t}" if show_pros
60
+ pump_up_down_res << _pump_condtion_satisfied?(r, s, t, k)
61
+ end
62
+
63
+ pump_up_down_res
64
+ end
65
+
66
+ def _pump_condtion_satisfied?(r, s, t, k)
67
+ (s.length.positive? && @lang.call(r + s * k + t))
68
+ end
30
69
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: falafel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.1
4
+ version: 0.0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abed Alkedda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-03 00:00:00.000000000 Z
11
+ date: 2023-08-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -28,7 +28,7 @@ files:
28
28
  - lib/rx.rb
29
29
  homepage: https://github.com/AbedAlkedda/AFS
30
30
  licenses:
31
- - Ruby
31
+ - ''
32
32
  metadata: {}
33
33
  post_install_message:
34
34
  rdoc_options: []
@@ -48,5 +48,6 @@ requirements: []
48
48
  rubygems_version: 3.3.26
49
49
  signing_key:
50
50
  specification_version: 4
51
- summary: Falafel is a gem to help you understand Automata better, hopefully
51
+ summary: Falafel is a gem that will hopefully help you better understand automata
52
+ and formal languages
52
53
  test_files: []